Esempio n. 1
0
//------------------------------------------------------------------------------
// function: proc_tod_init
//
// parameters: i_tod_node  Reference to TOD topology (FAPI targets included within)
//
// returns: FAPI_RC_SUCCESS if TOD topology is successfully initialized
//          else FAPI or ECMD error is sent through
//------------------------------------------------------------------------------
fapi::ReturnCode proc_tod_init(const tod_topology_node* i_tod_node)
{
    fapi::ReturnCode rc;

    FAPI_INF("proc_tod_init: Start");
    do
    {
        if (i_tod_node == NULL)
        {
            FAPI_ERR("proc_tod_setup: null node passed into function!");
            FAPI_SET_HWP_ERROR(rc, RC_PROC_TOD_NULL_NODE);
            break;
        }

        rc = proc_tod_clear_error_reg(i_tod_node);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_setup: Failure clearing TOD error registers!");
            break;
        }

        //Start configuring each node; (init_tod_node will recurse on each child)
        rc = init_tod_node(i_tod_node);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_setup: Failure initializing TOD!");
            break;
        }

    } while (0);

    FAPI_INF("proc_tod_init: End");
    return rc;
}
Esempio n. 2
0
/**
 * @brief Returns PROC_ABUS_CUPLL_REFCLKSEL_OFFSET data
 *
 * This is the offset within a PLL ring of some specific data
 *
 * @param[in]  i_procChip Reference to Processor Chip fapi target
 * @param[out] o_pVal     Pointer to data buffer filled in with attribute data
 * @param[in]  i_len      Size of o_pVal
 *
 * @return fapi::ReturnCode Indicating success or error
 */
fapi::ReturnCode get_PROC_ABUS_CUPLL_REFCLKSEL_OFFSET(
    const fapi::Target & i_procChip,
    void * o_pVal,
    const size_t i_len)
{
    fapi::ATTR_PROC_ABUS_CUPLL_REFCLKSEL_OFFSET_Type & o_val =
        *(reinterpret_cast<fapi::ATTR_PROC_ABUS_CUPLL_REFCLKSEL_OFFSET_Type *>(
            o_pVal));

    fapi::ReturnCode l_rc = pllInfoCheckSize(
        fapi::getPllRingInfo::PROC_ABUS_CUPLL_REFCLKSEL_OFFSET, i_len,
        sizeof(o_val));

    if (!l_rc)
    {
        fapi::ATTR_NAME_Type l_name = 0;
        fapi::ATTR_EC_Type l_ec = 0;

        l_rc = pllInfoGetChipNameEc(
            fapi::getPllRingInfo::PROC_ABUS_CUPLL_REFCLKSEL_OFFSET, i_procChip,
            l_name, l_ec);

        if (!l_rc)
        {
            // TODO RTC: 109249 Check to see if this data is valid for Naples
            // It was based off of Murano.
            // Data supplied by HW team
            if ( ((l_name == fapi::ENUM_ATTR_NAME_MURANO) &&
                  ((l_ec == 0x10) || (l_ec == 0x12) || (l_ec == 0x13) ||
                   (l_ec == 0x20) || (l_ec == 0x21))) ||
                 ((l_name == fapi::ENUM_ATTR_NAME_VENICE) &&
                   ((l_ec == 0x10) || ((l_ec >= 0x20) && (l_ec < 0x30)))) ||
                 ((l_name == fapi::ENUM_ATTR_NAME_NAPLES) &&
                  (l_ec == 0x10)) )
            {
                o_val[0] = 156;
                o_val[1] = 109;
                o_val[2] = 62;
            }
            else
            {
                FAPI_ERR("get_PROC_ABUS_CUPLL_REFCLKSEL_OFFSET: No data for Chip Name:EC %d:0x%x",
                         l_name, l_ec);
                const fapi::Target & PROC_CHIP = i_procChip;
                const fapi::ATTR_NAME_Type & CHIP_NAME = l_name;
                const fapi::ATTR_EC_Type & CHIP_EC = l_ec;
                FAPI_SET_HWP_ERROR(l_rc,
                    RC_GET_PROC_ABUS_CUPLL_REFCLKSEL_OFFSET_BAD_CHIP_NAME_EC);
            }
        }
    }

    return l_rc;
}
Esempio n. 3
0
//------------------------------------------------------------------------------
// function: proc_tod_clear_error_reg
//
// parameters: i_tod_node  Reference to TOD topology (FAPI targets included within)
//
// returns: FAPI_RC_SUCCESS if every TOD node is cleared of errors
//          else FAPI or ECMD error is sent through
//------------------------------------------------------------------------------
fapi::ReturnCode proc_tod_clear_error_reg(const tod_topology_node* i_tod_node)
{
    fapi::ReturnCode rc;
    ecmdDataBufferBase data(64);
    uint32_t rc_ecmd = 0;
    fapi::Target* target = i_tod_node->i_target;

    FAPI_INF("proc_tod_clear_error_reg: Start");
    do
    {
        if (i_tod_node == NULL)
        {
            FAPI_ERR("proc_tod_clear_error_reg: null node passed into function!");
            FAPI_SET_HWP_ERROR(rc, RC_PROC_TOD_NULL_NODE);
            break;
        }

        FAPI_DBG("proc_tod_clear_error_reg: Clear any previous errors from TOD_ERROR_REG_00040030");
        rc_ecmd |= data.flushTo1();
        if (rc_ecmd)
        {
            FAPI_ERR("proc_tod_clear_error_reg: Error 0x%08X in ecmdDataBuffer setup for TOD_ERROR_REG_00040030.",  rc_ecmd);
            rc.setEcmdError(rc_ecmd);
            break;
        }
        rc = fapiPutScom(*target, TOD_ERROR_REG_00040030, data);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_clear_error_reg: Could not write TOD_ERROR_REG_00040030.");
            break;
        }

        for (std::list<tod_topology_node*>::const_iterator child = (i_tod_node->i_children).begin();
             child != (i_tod_node->i_children).end();
             ++child)
        {
            tod_topology_node* tod_node = *child;
            rc = proc_tod_clear_error_reg(tod_node);
            if (!rc.ok())
            {
                FAPI_ERR("proc_tod_clear_error_reg: Failure clearing errors from downstream node!");
                break;
            }
        }
        if (!rc.ok())
        {
            break;  // error in above for loop
        }
    } while (0);

    FAPI_INF("proc_tod_clear_error_reg: End");
    return rc;
}
Esempio n. 4
0
/**
 * @brief Returns MEMB_DMI_CUPLL_REFCLKSEL_OFFSET data
 *
 * This is the offset within a PLL ring of some specific data
 *
 * @param[in]  i_membChip Reference to Membuf Chip fapi target
 * @param[out] o_pVal     Pointer to data buffer filled in with attribute data
 * @param[in]  i_len      Size of o_pVal
 *
 * @return fapi::ReturnCode Indicating success or error
 */
fapi::ReturnCode get_MEMB_DMI_CUPLL_REFCLKSEL_OFFSET(
    const fapi::Target & i_membChip,
    void * o_pVal,
    const size_t i_len)
{
    fapi::ATTR_MEMB_DMI_CUPLL_REFCLKSEL_OFFSET_Type & o_val =
        *(reinterpret_cast<fapi::ATTR_MEMB_DMI_CUPLL_REFCLKSEL_OFFSET_Type *>(
            o_pVal));

    fapi::ReturnCode l_rc = pllInfoCheckSize(
        fapi::getPllRingInfo::MEMB_DMI_CUPLL_REFCLKSEL_OFFSET, i_len,
        sizeof(o_val));

    if (!l_rc)
    {
        fapi::ATTR_NAME_Type l_name = 0;
        fapi::ATTR_EC_Type l_ec = 0;

        l_rc = pllInfoGetChipNameEc(
            fapi::getPllRingInfo::MEMB_DMI_CUPLL_REFCLKSEL_OFFSET, i_membChip,
            l_name, l_ec);

        if (!l_rc)
        {
            // Data supplied by HW team
            if ((l_name == fapi::ENUM_ATTR_NAME_CENTAUR) &&
                ((l_ec == 0x10) || (l_ec == 0x20) || (l_ec == 0x21)))
            {
                o_val = 92;
            }
            else
            {
                FAPI_ERR("get_MEMB_DMI_CUPLL_REFCLKSEL_OFFSET: No data for Chip Name:EC %d:0x%x",
                         l_name, l_ec);
                const fapi::Target & MEMBUF_CHIP = i_membChip;
                const fapi::ATTR_NAME_Type & CHIP_NAME = l_name;
                const fapi::ATTR_EC_Type & CHIP_EC = l_ec;
                FAPI_SET_HWP_ERROR(l_rc,
                    RC_GET_MEMB_DMI_CUPLL_REFCLKSEL_OFFSET_BAD_CHIP_NAME_EC);
            }
        }
    }

    return l_rc;
}
Esempio n. 5
0
/**
 * @brief Checks the user's buffer size
 *
 * @param[in] i_attr         Attribute ID (just used for tracing)
 * @param[in] i_actualSize   Actual buffer size
 * @param[in] i_expectedSize Expected buffer size
 *
 * @return fapi::ReturnCode Indicating success or error
 */
fapi::ReturnCode checkSize(const fapi::getSpdAttr::Attr i_attr,
                           const size_t i_actualSize,
                           const size_t i_expectedSize)
{
    fapi::ReturnCode l_rc;

    if (i_actualSize != i_expectedSize)
    {
        FAPI_ERR("getSpdAttrAccessor: Incorrect Attribute output buffer size %d:%d:%d",
                 i_attr, i_actualSize, i_expectedSize);
        const fapi::getSpdAttr::Attr & ATTR_ID = i_attr;
        const size_t & ACTUAL_SIZE = i_actualSize;
        const size_t & EXPECTED_SIZE = i_expectedSize;
        FAPI_SET_HWP_ERROR(l_rc, RC_GET_SPD_ACCESSOR_INVALID_OUTPUT_SIZE);
    }

    return l_rc;
}
Esempio n. 6
0
/**
 * @brief Checks the user's buffer size
 *
 * @param[in] i_attr         Attribute ID (just used for tracing)
 * @param[in] i_actualSize   Actual buffer size
 * @param[in] i_expectedSize Expected buffer size
 *
 * @return fapi::ReturnCode Indicating success or error
 */
fapi::ReturnCode pllInfoCheckSize(const fapi::getPllRingInfo::Attr i_attr,
                                  const size_t i_actualSize,
                                  const size_t i_expectedSize)
{
    fapi::ReturnCode l_rc;

    if (i_actualSize != i_expectedSize)
    {
        FAPI_ERR("getPllRingInfoAttr: Incorrect Attribute output buffer size %d:%d:%d",
                 i_attr, i_actualSize, i_expectedSize);
        const fapi::getPllRingInfo::Attr & ATTR_ID = i_attr;
        const size_t & ACTUAL_SIZE = i_actualSize;
        const size_t & EXPECTED_SIZE = i_expectedSize;
        FAPI_SET_HWP_ERROR(l_rc, RC_GET_PLL_RING_INFO_ATTR_INVALID_OUTPUT_SIZE);
    }

    return l_rc;
}
Esempio n. 7
0
//-----------------------------------------------------------------------------
// getSpdAttrAccessor HWP - See header file for details
//-----------------------------------------------------------------------------
fapi::ReturnCode getSpdAttrAccessor(const fapi::Target & i_dimm,
                                    const fapi::getSpdAttr::Attr i_attr,
                                    void * o_pVal,
                                    const size_t i_len)
{
    fapi::ReturnCode l_rc;

    fapi::ATTR_SPD_DRAM_DEVICE_TYPE_Type l_type = 0;
    l_rc = getDdrType(i_dimm, l_type);

    if (l_rc)
    {
        FAPI_ERR("getSpdAttrAccessor: Error from getDdrType for Attr ID 0x%02x",
                 i_attr);
    }
    else
    {
        switch (i_attr)
        {
        case fapi::getSpdAttr::SPD_SDRAM_BANKS:
            l_rc = get_SPD_SDRAM_BANKS(i_dimm, i_attr, o_pVal, i_len, l_type);
            break;
        case fapi::getSpdAttr::SPD_MODULE_NOMINAL_VOLTAGE:
            l_rc = get_SPD_MODULE_NOMINAL_VOLTAGE(i_dimm,  i_attr,o_pVal, i_len,
                                                  l_type);
            break;
        case fapi::getSpdAttr::SPD_CAS_LATENCIES_SUPPORTED:
            l_rc = get_SPD_CAS_LATENCIES_SUPPORTED(i_dimm, i_attr, o_pVal,
                                                   i_len, l_type);
            break;
        case fapi::getSpdAttr::SPD_MODULE_REVISION_CODE:
            l_rc = get_SPD_MODULE_REVISION_CODE(i_dimm,  i_attr, o_pVal, i_len,
                                                l_type);
            break;
        default:
            FAPI_ERR("getSpdAttrAccessor: Invalid Attribute ID 0x%02x", i_attr);
            const fapi::getSpdAttr::Attr & ATTR_ID = i_attr;
            FAPI_SET_HWP_ERROR(l_rc, RC_GET_SPD_ACCESSOR_INVALID_ATTRIBUTE_ID);
        }
    }

    return l_rc;
}
Esempio n. 8
0
/**
 * @brief Returns the DIMM DDR Type
 *
 * This function only supports DDR3 and DDR4
 *
 * @param[in]  i_dimm Reference to DIMM fapi target.
 * @param[out] o_type Filled in with the DIMM DDR Type.
 *
 * @return fapi::ReturnCode Indicating success or error
 */
fapi::ReturnCode getDdrType(const fapi::Target & i_dimm,
                            fapi::ATTR_SPD_DRAM_DEVICE_TYPE_Type & o_type)
{
    fapi::ReturnCode l_rc = FAPI_ATTR_GET(ATTR_SPD_DRAM_DEVICE_TYPE, &i_dimm,
                                          o_type);
    if (l_rc)
    {
        FAPI_ERR("getSpdAttrAccessor: Error querying DDR type");
    }
    else if ((o_type != fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR3) &&
             (o_type != fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR4))
    {
        FAPI_ERR("getSpdAttrAccessor: Invalid DIMM DDR Type 0x%02x", o_type);
        const fapi::Target & DIMM = i_dimm;
        const fapi::ATTR_SPD_DRAM_DEVICE_TYPE_Type & TYPE = o_type;
        FAPI_SET_HWP_ERROR(l_rc, RC_GET_SPD_ACCESSOR_INVALID_DDR_TYPE);
    }

    return l_rc;
}
Esempio n. 9
0
//-----------------------------------------------------------------------------
// getPllRingInfoAttr HWP - See header file for details
//-----------------------------------------------------------------------------
fapi::ReturnCode getPllRingInfoAttr(const fapi::Target & i_chip,
                                    const fapi::getPllRingInfo::Attr i_attr,
                                    void * o_pVal,
                                    const size_t i_len)
{
    fapi::ReturnCode l_rc;

    switch (i_attr)
    {
        case fapi::getPllRingInfo::PROC_DMI_CUPLL_PFD360_OFFSET:
            l_rc = get_PROC_DMI_CUPLL_PFD360_OFFSET(i_chip, o_pVal, i_len);
            break;
        case fapi::getPllRingInfo::PROC_DMI_CUPLL_REFCLKSEL_OFFSET:
            l_rc = get_PROC_DMI_CUPLL_REFCLKSEL_OFFSET(i_chip, o_pVal, i_len);
            break;
        case fapi::getPllRingInfo::PROC_ABUS_CUPLL_PFD360_OFFSET:
            l_rc = get_PROC_ABUS_CUPLL_PFD360_OFFSET(i_chip, o_pVal, i_len);
            break;
        case fapi::getPllRingInfo::PROC_ABUS_CUPLL_REFCLKSEL_OFFSET:
            l_rc = get_PROC_ABUS_CUPLL_REFCLKSEL_OFFSET(i_chip, o_pVal, i_len);
            break;
        case fapi::getPllRingInfo::MEMB_DMI_CUPLL_PFD360_OFFSET:
            l_rc = get_MEMB_DMI_CUPLL_PFD360_OFFSET(i_chip, o_pVal, i_len);
            break;
        case fapi::getPllRingInfo::MEMB_DMI_CUPLL_REFCLKSEL_OFFSET:
            l_rc = get_MEMB_DMI_CUPLL_REFCLKSEL_OFFSET(i_chip, o_pVal, i_len);
            break;
        case fapi::getPllRingInfo::MEMB_MEM_PLL_CFG_UPDATE_OFFSET:
            l_rc = get_MEMB_MEM_PLL_CFG_UPDATE_OFFSET(i_chip, o_pVal, i_len);
            break;
        default:
            FAPI_ERR("getPllRingInfoAttr: Invalid Attribute ID 0x%02x", i_attr);
            const fapi::getPllRingInfo::Attr & ATTR_ID = i_attr;
            FAPI_SET_HWP_ERROR(l_rc,
                               RC_GET_PLL_RING_INFO_ATTR_INVALID_ATTRIBUTE_ID);
    }

    return l_rc;
}
Esempio n. 10
0
// HWP entry point, comments in header
fapi::ReturnCode proc_pcie_config(
    const fapi::Target & i_target)
{
    fapi::ReturnCode rc;
    uint8_t pcie_enabled;
    uint8_t num_phb;

    // mark HWP entry
    FAPI_INF("proc_pcie_config: Start");

    do
    {
        // check for supported target type
        if (i_target.getType() != fapi::TARGET_TYPE_PROC_CHIP)
        {
            FAPI_ERR("proc_pcie_config: Unsupported target type");
            const fapi::Target & TARGET = i_target;
            FAPI_SET_HWP_ERROR(rc, RC_PROC_PCIE_CONFIG_INVALID_TARGET);
            break;
        }

        // query PCIE partial good attribute
        rc = FAPI_ATTR_GET(ATTR_PROC_PCIE_ENABLE,
                           &i_target,
                           pcie_enabled);
        if (!rc.ok())
        {
            FAPI_ERR("proc_pcie_config: Error querying ATTR_PROC_PCIE_ENABLE");
            break;
        }

        // initialize PBCQ/AIB, configure PBCQ FIRs (only if partial good
        // atttribute is set)
        if (pcie_enabled == fapi::ENUM_ATTR_PROC_PCIE_ENABLE_ENABLE)
        {
            // determine PHB configuration
            rc = FAPI_ATTR_GET(ATTR_PROC_PCIE_NUM_PHB,
                               &i_target,
                               num_phb);
            if (!rc.ok())
            {
                FAPI_ERR("proc_pcie_config: Error from FAPI_ATTR_GET (ATTR_PROC_PCIE_NUM_PHB)");
                break;
            }

            rc = proc_pcie_config_pbcq(i_target);
            if (!rc.ok())
            {
                FAPI_ERR("proc_pcie_config: Error from proc_pcie_config_pbcq");
                break;
            }

            rc = proc_pcie_config_pbcq_fir(i_target, num_phb);
            if (!rc.ok())
            {
                FAPI_ERR("proc_pcie_config: Error from proc_pcie_config_pbcq_fir");
                break;
            }

            rc = proc_a_x_pci_dmi_pll_setup_unmask_lock(
                i_target,
                PCIE_CHIPLET_0x09000000);
            if (!rc.ok())
            {
                FAPI_ERR("proc_pcie_config: Error from proc_a_x_pci_dmi_pll_setup_unmask_lock");
                break;
            }
        }
        else
        {
            FAPI_DBG("proc_pcie_config: Skipping initialization (partial good)");
        }

    } while(0);

    // mark HWP exit
    FAPI_INF("proc_pcie_config: End");
    return rc;
}
//------------------------------------------------------------------------------
// subroutine:
//      Check if the SBE is still running
//
// parameters: i_target           => slave chip target
//             o_still_running    => true if still running, false otherwise
//
// returns: FAPI_RC_SUCCESS if o_still_running is valid, else error
//------------------------------------------------------------------------------
    fapi::ReturnCode proc_check_slave_sbe_seeprom_complete_check_running(
        const fapi::Target & i_target,
        bool  & o_still_running )
    {
        // data buffer to hold register values
        ecmdDataBufferBase data(64);

        // return codes
        uint32_t rc_ecmd = 0;
        fapi::ReturnCode rc;

        do
        {
            FAPI_DBG("Checking SBE control reg");
            rc = fapiGetScom(i_target, PORE_SBE_CONTROL_0x000E0001, data);
            if(rc)
            {
                FAPI_ERR("Error reading SBE control reg\n");
                break;
            }

            // Bit 0 : 1 = stopped, 0 = running (or stopped at breakpoint)
            if( data.isBitClear(0) )
            {
                o_still_running = true;

                //If running, check for stopped at breakpoint
                FAPI_DBG("Checking SBE status reg");
                rc = fapiGetScom(i_target, PORE_SBE_STATUS_0x000E0000, data);
                if(rc)
                {
                    FAPI_ERR("Error reading SBE status reg\n");
                    break;
                }
                uint8_t state = 0;
                uint64_t address = data.getDoubleWord(0) &
                    0x0000FFFFFFFFFFFFull;
                rc_ecmd |= data.extractToRight( &state, 3, 4 );
                if(rc_ecmd)
                {
                    FAPI_ERR("Error (0x%x) extracting SBE status",
                             rc_ecmd);
                    rc.setEcmdError(rc_ecmd);
                    break;
                }

                if( state == SBE_STOPPED_AT_BREAKPOINT_0xB )
                {
                    FAPI_ERR("SBE stopped at breakpoint (address 0x%012llX)",
                             address);
                    const fapi::Target & CHIP_IN_ERROR = i_target;
                    FAPI_SET_HWP_ERROR(rc,
                RC_PROC_CHECK_SLAVE_SBE_SEEPROM_COMPLETE_STOPPED_AT_BREAKPOINT);
                    break;
                }
            }
            else
            {
                o_still_running = false;
            }
        } while(0);
        return rc;
    }
Esempio n. 12
0
//------------------------------------------------------------------------------
// function: proc_tod_save_config
//
// parameters: i_tod_node  Reference to TOD topology (FAPI targets included within)
//
// returns: FAPI_RC_SUCCESS if all registers were read and saved in node structure
//          else FAPI or ECMD error is sent through
//------------------------------------------------------------------------------
fapi::ReturnCode proc_tod_save_config(tod_topology_node* i_tod_node)
{
    fapi::ReturnCode rc;

    FAPI_DBG("proc_tod_save_config: Start");
    do
    {
        if (i_tod_node == NULL)
        {
            FAPI_ERR("proc_tod_save_config: null node passed into function!");
            FAPI_SET_HWP_ERROR(rc, RC_PROC_TOD_NULL_NODE);
            break;
        }
        fapi::Target* target = i_tod_node->i_target;

        rc = proc_tod_save_single_reg(*target, TOD_M_PATH_CTRL_REG_00040000, i_tod_node->o_todRegs.tod_m_path_ctrl_reg);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_save_config: Error saving TOD_M_PATH_CTRL_REG_00040000...");
            break;
        }

        rc = proc_tod_save_single_reg(*target, TOD_PRI_PORT_0_CTRL_REG_00040001,i_tod_node->o_todRegs.tod_pri_port_0_ctrl_reg);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_save_config: Error saving TOD_PRI_PORT_0_CTRL_REG_00040001...");
            break;
        }

        rc = proc_tod_save_single_reg(*target, TOD_PRI_PORT_1_CTRL_REG_00040002,i_tod_node->o_todRegs.tod_pri_port_1_ctrl_reg);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_save_config: Error saving TOD_PRI_PORT_1_CTRL_REG_00040002...");
            break;
        }

        rc = proc_tod_save_single_reg(*target, TOD_SEC_PORT_0_CTRL_REG_00040003,i_tod_node->o_todRegs.tod_sec_port_0_ctrl_reg);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_save_config: Error saving TOD_SEC_PORT_0_CTRL_REG_00040003...");
            break;
        }

        rc = proc_tod_save_single_reg(*target, TOD_SEC_PORT_1_CTRL_REG_00040004,i_tod_node->o_todRegs.tod_sec_port_1_ctrl_reg);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_save_config: Error saving TOD_SEC_PORT_1_CTRL_REG_00040004...");
            break;
        }

        rc = proc_tod_save_single_reg(*target, TOD_S_PATH_CTRL_REG_00040005,i_tod_node->o_todRegs.tod_s_path_ctrl_reg);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_save_config: Error saving TOD_S_PATH_CTRL_REG_00040005...");
            break;
        }

        rc = proc_tod_save_single_reg(*target, TOD_I_PATH_CTRL_REG_00040006,i_tod_node->o_todRegs.tod_i_path_ctrl_reg);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_save_config: Error saving TOD_I_PATH_CTRL_REG_00040006...");
            break;
        }

        rc = proc_tod_save_single_reg(*target, TOD_PSS_MSS_CTRL_REG_00040007,i_tod_node->o_todRegs.tod_pss_mss_ctrl_reg);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_save_config: Error saving TOD_PSS_MSS_CTRL_REG_00040007...");
            break;
        }

        rc = proc_tod_save_single_reg(*target, TOD_CHIP_CTRL_REG_00040010,i_tod_node->o_todRegs.tod_chip_ctrl_reg);
        if (!rc.ok())
        {
            FAPI_ERR("proc_tod_save_config: Error saving TOD_CHIP_CTRL_REG_00040010...");
            break;
        }

        // Recurse to save children configuration
        for (std::list<tod_topology_node*>::iterator child = (i_tod_node->i_children).begin();
             child != (i_tod_node->i_children).end();
             ++child)
        {
            tod_topology_node* tod_node = *child;
            rc = proc_tod_save_config(tod_node);
            if (!rc.ok())
            {
                FAPI_ERR("proc_tod_save_config: Failure saving downstream configurations!");
                break;
            }
        }
        if (!rc.ok())
        {
            break;  // error in above for loop
        }
    } while(0);

    FAPI_DBG("proc_tod_save_config: End");
    return rc;
}
Esempio n. 13
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;
}
Esempio n. 14
0
//------------------------------------------------------------------------------
// HWP entry point
//------------------------------------------------------------------------------
fapi::ReturnCode proc_fab_iovalid(
    std::vector<proc_fab_iovalid_proc_chip>& i_proc_chips,
    bool i_set_not_clear)
{
    // return code
    fapi::ReturnCode rc;
    // iterator for HWP input vector
    std::vector<proc_fab_iovalid_proc_chip>::const_iterator iter;

    // partial good attributes
    uint8_t abus_enable_attr;
    uint8_t xbus_enable_attr;
    bool x_changed = false;
    bool a_changed = false;

    // mark HWP entry
    FAPI_IMP("proc_fab_iovalid: Entering ...");

    do
    {
        // loop over all chips in input vector
        for (iter = i_proc_chips.begin();
             iter != i_proc_chips.end();
             iter++)
        {
            // process X links
            if (iter->x0 ||
                iter->x1 ||
                iter->x2 ||
                iter->x3)
            {
                // query XBUS partial good attribute
                rc = FAPI_ATTR_GET(ATTR_PROC_X_ENABLE,
                                   &(iter->this_chip),
                                   xbus_enable_attr);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_fab_iovalid: Error querying ATTR_PROC_X_ENABLE");
                    break;
                }

                if (xbus_enable_attr != fapi::ENUM_ATTR_PROC_X_ENABLE_ENABLE)
                {
                    FAPI_ERR("proc_fab_iovalid: Partial good attribute error");
                    const fapi::Target & TARGET = iter->this_chip;
                    FAPI_SET_HWP_ERROR(rc, RC_PROC_FAB_IOVALID_X_PARTIAL_GOOD_ERR);
                    break;
                }

                rc = proc_fab_iovalid_manage_x_links(*iter, i_set_not_clear);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_fab_iovalid: Error from proc_fab_iovalid_manage_x_links");
                    break;
                }

                rc = proc_fab_iovalid_manage_x_fir(*iter, i_set_not_clear);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_fab_iovalid: Error from proc_fab_iovalid_manage_x_fir");
                    break;
                }

                x_changed = true;
            }

            // process A links
            if (iter->a0 ||
                iter->a1 ||
                iter->a2)
            {
                // query ABUS partial good attribute
                rc = FAPI_ATTR_GET(ATTR_PROC_A_ENABLE,
                                   &(iter->this_chip),
                                   abus_enable_attr);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_fab_iovalid: Error querying ATTR_PROC_A_ENABLE");
                    break;
                }

                if (abus_enable_attr != fapi::ENUM_ATTR_PROC_A_ENABLE_ENABLE)
                {
                    FAPI_ERR("proc_fab_iovalid: Partial good attribute error");
                    const fapi::Target & TARGET = iter->this_chip;
                    FAPI_SET_HWP_ERROR(rc, RC_PROC_FAB_IOVALID_A_PARTIAL_GOOD_ERR);
                    break;
                }

                rc = proc_fab_iovalid_manage_a_links(*iter, i_set_not_clear);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_fab_iovalid: Error from proc_fab_iovalid_manage_a_links");
                    break;
                }

                rc = proc_fab_iovalid_manage_a_fir(*iter, i_set_not_clear);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_fab_iovalid: Error from proc_fab_iovalid_manage_a_fir");
                    break;
                }

                a_changed = true;
            }

            if (x_changed || a_changed)
            {
                rc = proc_fab_iovalid_manage_ras_fir(*iter, i_set_not_clear);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_fab_iovalid: Error from proc_fab_iovalid_manage_ras_fir");
                    break;
                }
            }
        }
    } while(0);

    // log function exit
    FAPI_IMP("proc_fab_iovalid: Exiting ...");
    return 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;
}
Esempio n. 16
0
  //------------------------------------------------------------------------------
  // name: proc_mpipl_chip_cleanup
  //------------------------------------------------------------------------------
  // purpose: 
  // To enable MCD recovery
  //
  // Note: PHBs are left in ETU reset state after executing proc_mpipl_nest_cleanup, which runs before this procedure.  PHYP releases PHBs from ETU reset post HostBoot IPL.
  //
  // SCOM regs
  //
  // 1) MCD even recovery control register
  // 0000000002013410 (SCOM)
  // bit 0 (MCD_REC_EVEN_ENABLE): 0 to 1 transition needed to start, reset to 0 at end of request.
  // bit 5 (MCD_REC_EVEN_REQ_PEND)
  //
  //
  // 2) MCD odd recovery control register
  // 0000000002013411 (SCOM)
  // bit 0 (MCD_REC_ODD_ENABLE): 0 to 1 transition needed to start, reset to 0 at end of request.
  // bit 5 (MCD_REC_ODD_REQ_PEND)
  //
  // 3) Clear PCI Nest FIR registers
  // 02012000 (SCOM) 
  // 02012400 (SCOM) 
  // 02012800 (SCOM) 
  //
  // parameters: 
  // 'i_target' is reference to chip target
  //
  // returns:
  // FAPI_RC_SUCCESS (success, MCD recovery enabled for odd and even slices)
  //
  // RC_MCD_RECOVERY_NOT_DISABLED_RC (MCD recovery for even or odd slice is not disabled; therefore can't re-enable MCD recovery)
  // (Note: refer to file eclipz/chips/p8/working/procedures/xml/error_info/proc_mpipl_chip_cleanup_errors.xml)
  // 
  // getscom/putscom fapi errors
  // fapi error assigned from eCMD function failure
  // 
  //------------------------------------------------------------------------------
  fapi::ReturnCode proc_mpipl_chip_cleanup(const fapi::Target &i_target){
    const char *procedureName = "proc_mpipl_chip_cleanup"; //Name of this procedure
    fapi::ReturnCode rc; //fapi return code value
    uint32_t rc_ecmd = 0;    //ecmd return code value
    const uint32_t data_size = 64; //Size of data buffer
    const int MAX_MCD_DIRS = 2; //Max of 2 MCD Directories (even and odd)
    ecmdDataBufferBase fsi_data[MAX_MCD_DIRS];
    const uint64_t ARY_MCD_RECOVERY_CTRL_REGS_ADDRS[MAX_MCD_DIRS] = {
      0x0000000002013410, //MCD even recovery control register address
      0x0000000002013411  //MCD odd recovery control register address
    };     
    const uint32_t MCD_RECOVERY_CTRL_REG_BIT_POS0 = 0; //Bit 0 of MCD even and odd recovery control regs
    const char *ARY_MCD_DIR_STRS[MAX_MCD_DIRS] = {
      "Even", //Ptr to char string "Even" for even MCD
      "Odd"   //Ptr to char string "Odd" for odd MCD
    }; 
    const int MAX_PHBS = 3;
    const uint64_t PCI_NEST_FIR_REG_ADDRS[MAX_PHBS] = {
      0x02012000,
      0x02012400,
      0x02012800
    };     
    
    do {
      //Set bit length for 64-bit buffers
      rc_ecmd = fsi_data[0].setBitLength(data_size);
      rc_ecmd |= fsi_data[1].setBitLength(data_size);
      if(rc_ecmd) {
        rc.setEcmdError(rc_ecmd);
        break;
      }
  
      //Verify MCD recovery was previously disabled for even and odd slices
      //If not, this is an error condition
      for (int counter = 0; counter < MAX_MCD_DIRS; counter++) {
        FAPI_DBG("Verifying MCD %s Recovery is disabled, target=%s", ARY_MCD_DIR_STRS[counter], i_target.toEcmdString());
        
        //Get data from MCD Even or Odd Recovery Ctrl reg
        rc = fapiGetScom(i_target, ARY_MCD_RECOVERY_CTRL_REGS_ADDRS[counter], fsi_data[counter]);
        if (!rc.ok()) {
          FAPI_ERR("%s: fapiGetScom error (addr: 0x%08llX), target=%s", procedureName, ARY_MCD_RECOVERY_CTRL_REGS_ADDRS[counter], i_target.toEcmdString());
          break;
        }
        
  
        //Check whether bit 0 is 0, meaning MCD recovery is disabled as expected
        if( fsi_data[counter].getBit(MCD_RECOVERY_CTRL_REG_BIT_POS0) ) {
          FAPI_ERR("%s: MCD %s Recovery not disabled as expected, target=%s", procedureName, ARY_MCD_DIR_STRS[counter], i_target.toEcmdString());
          const fapi::Target & CHIP_TARGET = i_target;
  	  const uint64_t & MCD_RECOV_CTRL_REG_ADDR = ARY_MCD_RECOVERY_CTRL_REGS_ADDRS[counter];
          ecmdDataBufferBase & MCD_RECOV_CTRL_REG_DATA = fsi_data[counter];
          FAPI_SET_HWP_ERROR(rc, RC_MPIPL_MCD_RECOVERY_NOT_DISABLED_RC);
          break;
        }
      }
      if(!rc.ok()) {
        break;
      }
  
      //Assert bit 0 of MCD Recovery Ctrl regs to enable MCD recovery
      for (int counter = 0; counter < MAX_MCD_DIRS; counter++) {
        FAPI_DBG("Enabling MCD %s Recovery, target=%s", ARY_MCD_DIR_STRS[counter], i_target.toEcmdString());
        
        //Assert bit 0 of MCD Even or Odd Recovery Control reg to enable recovery
        rc_ecmd = fsi_data[counter].setBit(MCD_RECOVERY_CTRL_REG_BIT_POS0 );
        if(rc_ecmd) {
          FAPI_ERR("%s: Error (%u) asserting bit pos %u in ecmdDataBufferBase that stores value of MCD %s Recovery Control reg (addr: 0x%08llX), target=%s", procedureName, rc_ecmd, MCD_RECOVERY_CTRL_REG_BIT_POS0, ARY_MCD_DIR_STRS[counter], ARY_MCD_RECOVERY_CTRL_REGS_ADDRS[counter], i_target.toEcmdString());
          rc.setEcmdError(rc_ecmd);
          break;
        }
        
        //Write data to MCD Even or Odd Recovery Control reg
        rc = fapiPutScom(i_target, ARY_MCD_RECOVERY_CTRL_REGS_ADDRS[counter], fsi_data[counter]);
        if (!rc.ok()) {
          FAPI_ERR("%s: fapiPutScom error (addr: 0x%08llX), target=%s", procedureName, ARY_MCD_RECOVERY_CTRL_REGS_ADDRS[counter], i_target.toEcmdString());
          break;
        }
      }
      if(!rc.ok()) {
        break;
      }
  
      // SW227429: clear PCI Nest FIR registers
      // hostboot is blindly sending EOIs in order to ensure no interrupts are pending when  PHYP starts up again
      // with ETU held in reset, these get trapped in PCI and force a freeze to occur (PCI Nest FIR(14))
      // clearing the FIR should remove the freeze condition
      rc_ecmd = fsi_data[0].flushTo0();
      if (rc_ecmd) {
        FAPI_ERR("%s: Error (%u) forming PCI Nest FIR clear data buffer, target=%s", procedureName, rc_ecmd, i_target.toEcmdString());
        rc.setEcmdError(rc_ecmd);
        break;
      }
      
      for (int counter = 0; counter < MAX_PHBS; counter++) {
        FAPI_DBG("Clearing PCI%d Nest FIR, target=%s", counter, i_target.toEcmdString());
        rc = fapiPutScom(i_target, PCI_NEST_FIR_REG_ADDRS[counter], fsi_data[0]);
        if (!rc.ok()) {
          FAPI_ERR("%s: fapiPutScom error (addr: 0x%08llX), target=%s", procedureName, PCI_NEST_FIR_REG_ADDRS[counter], i_target.toEcmdString());
          break;
        }
      }
    } while(0);

    FAPI_IMP("Exiting %s", procedureName);

    return rc;
  }
//------------------------------------------------------------------------------
// function:
//      Check if the SBE is still running
//      Wait 1 sec, then check again if still running
//      When stopped, check if the SBE halt code, istep, and substep are correct
//
// parameters: i_target           => slave chip target
//             i_pSEEPROM         => pointer to the seeprom image (for errors)
//             i_wait_in_ms       => pointer to the seeprom image (for errors)
//
// returns: FAPI_RC_SUCCESS if the slave SBE stopped with success at the correct
//          location, else error
//------------------------------------------------------------------------------
    fapi::ReturnCode proc_check_slave_sbe_seeprom_complete(
        const fapi::Target & i_target,
        const void         * i_pSEEPROM,
        const size_t       i_wait_in_ms)
    {
        // data buffer to hold register values
        ecmdDataBufferBase data(64);

        // return codes
        uint32_t rc_ecmd = 0;
        fapi::ReturnCode rc;

        // track if procedure has cleared I2C master bus fence
        bool i2cm_bus_fence_cleared = false;

        // mark function entry
        FAPI_INF("Entry");

        do
        {
            //Check if the SBE is still running.  Loop until stopped
            //or loop time is exceeded.  
            bool still_running = true;
            size_t loop_time = 0;
            rc = proc_check_slave_sbe_seeprom_complete_check_running(
                   i_target,
                   still_running );
            if( rc )
            {
                break;
            }

            while (still_running && (loop_time < i_wait_in_ms))
            {
                //Not done -- sleep 10ms, then check again
                loop_time += MS_TO_FINISH;
                rc = fapiDelay(NS_TO_FINISH, SIM_CYCLES_TO_FINISH);
                if( rc )
                {
                    FAPI_ERR("Error with delay\n");
                    break;
                }

                rc = proc_check_slave_sbe_seeprom_complete_check_running(
                       i_target,
                       still_running );
                if( rc )
                {
                    break;
                }
            }

            //Break if took an error
            if( rc )
            {
                break;
            }

            FAPI_INF("SBE is running [%d], wait time in ms[%zd]",
                     still_running, loop_time);

            //Give up if we're still running
            if( still_running )
            {
                FAPI_ERR(
                        "SBE still running after waiting (%zdns, %lld cycles)",
                        loop_time,
                        loop_time/MS_TO_FINISH*SIM_CYCLES_TO_FINISH );

                const fapi::Target & CHIP_IN_ERROR = i_target;
                FAPI_SET_HWP_ERROR(rc,
                      RC_PROC_CHECK_SLAVE_SBE_SEEPROM_COMPLETE_STILL_RUNNING);
                break;
            } //end if(still_running)

            //SBE is stopped. Let's see where
            uint8_t  halt_code = 0;
            uint16_t istep_num = 0;
            uint8_t  substep_num = 0;

            // before analysis proceeds, make sure that I2C master bus fence is cleared
            FAPI_EXEC_HWP(rc, proc_reset_i2cm_bus_fence, i_target);
            if (!rc.ok())
            {
                FAPI_ERR("Error from proc_reset_i2cm_bus_fence");
                break;
            }
            // mark that fence has been cleared
            i2cm_bus_fence_cleared = true;

            //Get current location from SBE VITAL
            rc = proc_check_slave_sbe_seeprom_complete_get_location(
                i_target,
                halt_code,
                istep_num,
                substep_num );
            if( rc )
            {
                FAPI_ERR("Unable to get the current SBE location");
                break;
            }

            //Did it stop with success?
            if( halt_code != SBE_EXIT_SUCCESS_0xF )
            {
                FAPI_ERR(
                    "SBE halted with error %i (istep 0x%X, substep %i)", 
                    halt_code,
                    istep_num,
                    substep_num);
                //Get the error code from the SBE code
                FAPI_EXEC_HWP(rc, proc_extract_sbe_rc, i_target, NULL, i_pSEEPROM, SBE);
                break;
            }
            //Halt code was success

            //Did it stop in the correct istep?
            if(( istep_num != PROC_SBE_CHECK_MASTER_MAGIC_ISTEP_NUM ) &&
               ( istep_num != PROC_SBE_ENABLE_PNOR_MAGIC_ISTEP_NUM ) &&
               ( istep_num != PROC_SBE_EX_HOST_RUNTIME_SCOM_MAGIC_ISTEP_NUM ))
            {
                FAPI_ERR(
                    "SBE halted in wrong istep (istep 0x%X, substep %i)", 
                    istep_num,
                    substep_num);
                const fapi::Target & CHIP_IN_ERROR = i_target;
                uint16_t & ISTEP_NUM = istep_num;
                uint8_t & SUBSTEP_NUM = substep_num;
                FAPI_SET_HWP_ERROR(rc,
                        RC_PROC_CHECK_SLAVE_SBE_SEEPROM_COMPLETE_BAD_ISTEP_NUM);
                break;
            }
            //Istep is correct

            //Did it stop in the correct substep?
            if( (( istep_num == PROC_SBE_CHECK_MASTER_MAGIC_ISTEP_NUM ) &&
                 ( substep_num != SUBSTEP_CHECK_MASTER_SLAVE_CHIP )) ||
                (( istep_num == PROC_SBE_ENABLE_PNOR_MAGIC_ISTEP_NUM ) &&
                 ( substep_num != SUBSTEP_ENABLE_PNOR_SLAVE_CHIP )))
            {
                FAPI_ERR(
                    "SBE halted in wrong substep (istep 0x%X, substep %i)", 
                    istep_num,
                    substep_num);
                const fapi::Target & CHIP_IN_ERROR = i_target;
                uint16_t & ISTEP_NUM = istep_num;
                uint8_t & SUBSTEP_NUM = substep_num;
                FAPI_SET_HWP_ERROR(rc,
                      RC_PROC_CHECK_SLAVE_SBE_SEEPROM_COMPLETE_BAD_SUBSTEP_NUM);
                break;
            }
            //Substep is correct

            //Looks good!

            // Reset the SBE so it can be used for MPIPL if needed
            rc_ecmd |= data.flushTo0();
            rc_ecmd |= data.setBit(0);

            if(rc_ecmd)
            {
                FAPI_ERR("Error (0x%x) setting up ecmdDataBufferBase", rc_ecmd);
                rc.setEcmdError(rc_ecmd);
                break;
            }
            rc = fapiPutScom(i_target, PORE_SBE_RESET_0x000E0002, data);
            if(!rc.ok())
            {
                FAPI_ERR("Scom error resetting SBE\n");
                break;
            }
        } while (0);

        // if an error occurred prior to the I2C master bus fence
        // being cleared, attempt to clear it prior to exit
        if (!rc.ok() && !i2cm_bus_fence_cleared)
        {
            // discard rc, return that of original fail
            fapi::ReturnCode rc_unused;
            FAPI_EXEC_HWP(rc_unused, proc_reset_i2cm_bus_fence, i_target);
        }

        // mark function exit
        FAPI_INF("Exit");
        return rc;
    }
Esempio n. 18
0
//------------------------------------------------------------------------------
// function: init_tod_node
//
// parameters: i_tod_node  Reference to TOD topology (FAPI targets included within)
//
// returns: FAPI_RC_SUCCESS if TOD topology is successfully initialized
//          else FAPI or ECMD error is sent through
//------------------------------------------------------------------------------
fapi::ReturnCode init_tod_node(const tod_topology_node* i_tod_node)
{
    fapi::ReturnCode rc;
    ecmdDataBufferBase data(64);
    uint32_t rc_ecmd = 0;
    uint32_t tod_init_pending_count = 0; // Timeout counter for bits that are cleared by hardware
    fapi::Target* target = i_tod_node->i_target;

    FAPI_INF("configure_tod_node: Start: Configuring %s", target->toEcmdString());

    do
    {
        const bool is_mdmt = (i_tod_node->i_tod_master && i_tod_node->i_drawer_master);

        if (is_mdmt)
        {
            FAPI_INF("init_tod_node: Master: Chip TOD step checkers enable");
            rc_ecmd |= data.flushTo0();
            rc_ecmd |= data.setBit(0);
            if (rc_ecmd)
            {
                FAPI_ERR("init_tod_node: Error 0x%08X in ecmdDataBuffer setup for TOD_TX_TTYPE_2_REG_00040013 SCOM.",  rc_ecmd);
                rc.setEcmdError(rc_ecmd);
                break;
            }
            rc = fapiPutScom(*target, TOD_TX_TTYPE_2_REG_00040013, data);
            if (!rc.ok())
            {
                FAPI_ERR("init_tod_node: Could not write TOD_TX_TTYPE_2_REG_00040013.");
                break;
            }

            FAPI_INF("init_tod_node: Master: switch local Chip TOD to 'Not Set' state");
            rc_ecmd |= data.flushTo0();
            rc_ecmd |= data.setBit(TOD_LOAD_TOD_MOD_REG_FSM_LOAD_TOD_MOD_TRIG);
            if (rc_ecmd)
            {
                FAPI_ERR("init_tod_node: Master: Error 0x%08X in ecmdDataBuffer setup for TOD_LOAD_TOD_MOD_REG_00040018 SCOM.",  rc_ecmd);
                rc.setEcmdError(rc_ecmd);
                break;
            }
            rc = fapiPutScom(*target, TOD_LOAD_TOD_MOD_REG_00040018, data);
            if (!rc.ok())
            {
                FAPI_ERR("init_tod_node: Master: Could not write TOD_LOAD_TOD_MOD_REG_00040018");
                break;
            }
            FAPI_INF("init_tod_node: Master: switch all Chip TOD in the system to 'Not Set' state");
            rc_ecmd |= data.flushTo0();
            rc_ecmd |= data.setBit(0);
            if (rc_ecmd)
            {
                FAPI_ERR("init_tod_node: Master: Error 0x%08X in ecmdDataBuffer setup for TOD_TX_TTYPE_5_REG_00040016 SCOM.",  rc_ecmd);
                rc.setEcmdError(rc_ecmd);
                break;
            }
            rc = fapiPutScom(*target, TOD_TX_TTYPE_5_REG_00040016, data);
            if (!rc.ok())
            {
                FAPI_ERR("init_tod_node: Master: Could not write TOD_TX_TTYPE_5_REG_00040016");
                break;
            }
   
            FAPI_INF("init_tod_node: Master: Chip TOD load value (move TB to TOD)");
            rc_ecmd |= data.flushTo0();
            rc_ecmd |= data.setWord(0,0x00000000);
            rc_ecmd |= data.setWord(1,0x00003FF0); // bits 51:59 must be 1s
            if (rc_ecmd)
            {
                FAPI_ERR("init_tod_node: Master: Error 0x%08X in ecmdDataBuffer setup for TOD_LOAD_TOD_REG_00040021 SCOM.",  rc_ecmd);
                rc.setEcmdError(rc_ecmd);
                break;
            }
            rc = fapiPutScom(*target, TOD_LOAD_TOD_REG_00040021, data);
            if (!rc.ok())
            {
                FAPI_ERR("init_tod_node: Master: Could not write TOD_LOAD_TOD_REG_00040021");
                break;
            }
            FAPI_INF("init_tod_node: Master: Chip TOD start_tod (switch local Chip TOD to 'Running' state)");
            rc_ecmd |= data.flushTo0();
            rc_ecmd |= data.setBit(TOD_START_TOD_REG_FSM_START_TOD_TRIGGER);
            if (rc_ecmd)
            {
                FAPI_ERR("init_tod_node: Master: Error 0x%08X in ecmdDataBuffer setup for TOD_START_TOD_REG_00040022 SCOM.",  rc_ecmd);
                rc.setEcmdError(rc_ecmd);
                break;
            }
            rc = fapiPutScom(*target, TOD_START_TOD_REG_00040022, data);
            if (!rc.ok())
            {
                FAPI_ERR("init_tod_node: Master: Could not write TOD_START_TOD_REG_00040022");
                break;
            }

            FAPI_INF("init_tod_node: Master: Send local Chip TOD value to all Chip TODs");
            rc_ecmd |= data.flushTo0();
            rc_ecmd |= data.setBit(0);
            if (rc_ecmd)
            {
                FAPI_ERR("init_tod_node: Master: Error 0x%08X in ecmdDataBuffer setup for TOD_TX_TTYPE_4_REG_00040015",  rc_ecmd);
                rc.setEcmdError(rc_ecmd);
                break;
            }
            rc = fapiPutScom(*target, TOD_TX_TTYPE_4_REG_00040015, data);
            if (!rc.ok())
            {
                FAPI_ERR("init_tod_node: Master: Could not write TOD_TX_TTYPE_4_REG_00040015");
                break;
            }
        }

        FAPI_INF("init_tod_node: Check TOD is Running");
        tod_init_pending_count = 0;
        while (tod_init_pending_count < PROC_TOD_UTIL_TIMEOUT_COUNT)
        {
            FAPI_DBG("init_tod_node: Waiting for TOD to assert TOD_FSM_REG_TOD_IS_RUNNING...");
   
            rc = fapiDelay(PROC_TOD_UTILS_HW_NS_DELAY,
                           PROC_TOD_UTILS_SIM_CYCLE_DELAY);
            if (!rc.ok())
            {
                FAPI_ERR("init_tod_node: fapiDelay error");
                break;
            }
            rc = fapiGetScom(*target, TOD_FSM_REG_00040024, data);
            if (!rc.ok())
            {
                FAPI_ERR("init_tod_node: Could not retrieve TOD_FSM_REG_00040024");
                break;
            }
            if (data.isBitSet(TOD_FSM_REG_TOD_IS_RUNNING))
            {
                FAPI_INF("init_tod_node: TOD is running!");
                break;
            }
            ++tod_init_pending_count;
        }
        if (!rc.ok())
        {
            break;  // error in above while loop
        }
        if (tod_init_pending_count>=PROC_TOD_UTIL_TIMEOUT_COUNT)
        {
                FAPI_ERR("init_tod_node: TOD is not running! (It should be)");
                const fapi::Target & CHIP_TARGET = *target;
                FAPI_SET_HWP_ERROR(rc, RC_PROC_TOD_INIT_NOT_RUNNING);
                break;
        }

        FAPI_INF("init_tod_node: clear TTYPE#2 and TTYPE#4 status");
        rc_ecmd |= data.flushTo0();
        rc_ecmd |= data.setBit(TOD_ERROR_REG_RX_TTYPE_2);
        rc_ecmd |= data.setBit(TOD_ERROR_REG_RX_TTYPE_4);
        if (rc_ecmd)
        {
            FAPI_ERR("init_tod_node: Error 0x%08X in ecmdDataBuffer setup for TOD_ERROR_REG_00040030.",  rc_ecmd);
            rc.setEcmdError(rc_ecmd);
            break;
        }
        rc = fapiPutScom(*target, TOD_ERROR_REG_00040030, data);
        if (!rc.ok())
        {
            FAPI_ERR("init_tod_node: Could not write TOD_ERROR_REG_00040030.");
            break;
        }

        FAPI_INF("init_tod_node: checking for TOD errors");
        rc = fapiGetScom(*target, TOD_ERROR_REG_00040030, data);
        if (!rc.ok())
        {
            FAPI_ERR("init_tod_node: Could not read TOD_ERROR_REG_00040030.");
            break;
        }
        if (data.getDoubleWord(0) != 0)
        {
            FAPI_ERR("init_tod_node: FIR bit active! (TOD_ERROR_REG = 0x%016llX)",data.getDoubleWord(0));
            const fapi::Target & CHIP_TARGET = *target;
            const uint64_t TOD_ERROR_REG = data.getDoubleWord(0);
            FAPI_SET_HWP_ERROR(rc, RC_PROC_TOD_INIT_ERROR);
            break;
        }

        // Finish configuring downstream nodes
        for (std::list<tod_topology_node*>::const_iterator child = (i_tod_node->i_children).begin();
             child != (i_tod_node->i_children).end();
             ++child)
        {
            tod_topology_node* tod_node = *child;
            rc = init_tod_node(tod_node);
            if (!rc.ok())
            {
                FAPI_ERR("init_tod_node: Failure configuring downstream node!");
                break;
            }
        }
        if (!rc.ok())
        {
            break;  // error in above for loop
        }

    } while(0);

    FAPI_INF("init_tod_node: End");
    return rc;
}
// HWP entry point, comments in header
fapi::ReturnCode proc_tp_collect_dbg_data(const fapi::Target & i_target,
                                          fapi::ReturnCode & o_rc)
{
    fapi::ReturnCode rc;
    uint32_t rc_ecmd = 0;

    uint8_t chip_type;
    uint8_t dd_level;
	ecmdDataBufferBase ring_data;
    ecmdDataBufferBase spy_data;
    std::vector<std::pair<uint32_t, uint32_t> > spy_offsets;
	ecmdDataBufferBase fsi_data(32);
	ecmdDataBufferBase scom_data(64);

    // mark HWP entry
    FAPI_INF("proc_tp_collect_dbg_data: Start");

    do
    {
		// Setting Prevent AutoStart Bit to avoid scan chain corruption
        rc = fapiGetCfamRegister(i_target, CFAM_FSI_SBE_VITAL_0x0000281C, fsi_data);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: fapiGetCfamRegister error (CFAM_FSI_SBE_VITAL_0x0000281c)");
            break;
        }
        
        rc_ecmd |= fsi_data.setBit(1);
        rc_ecmd |= fsi_data.setBit(3);
        if (rc_ecmd)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: Error 0x%x setting up FSI SBE Vital Register",
                     rc_ecmd);
            rc.setEcmdError(rc_ecmd);
            break;
        }

        rc = fapiPutCfamRegister(i_target, CFAM_FSI_SBE_VITAL_0x0000281C, fsi_data);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: fapiPutCfamRegister error (CFAM_FSI_SBE_VITAL_0x0000281C)");
            break;
        }
		
		
        // Setting FSI Shift Speed
        rc = fapiGetCfamRegister(i_target, CFAM_FSI_SHIFT_CTRL_0x00000C10, fsi_data);
        if (rc)
        {
        	FAPI_ERR("proc_tp_collect_dbg_data: fapiGetCfamRegister error (CFAM_FSI_SHIFT_CTRL_0x00000C10)");
            break;
        }
        
        rc_ecmd |= fsi_data.setWord(0,PROC_TP_COLLECT_DBG_DATA_FSI_SHIFT_CTRL);
        if (rc_ecmd)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: Error 0x%x setting up FSI SHIFT CTRL register data buffer",
                     rc_ecmd);
            rc.setEcmdError(rc_ecmd);
            break;
        }

        rc = fapiPutCfamRegister(i_target, CFAM_FSI_SHIFT_CTRL_0x00000C10, fsi_data);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: fapiPutCfamRegister error (CFAM_FSI_SHIFT_CTRL_0x00000C10)");
            break;
        }
        
        // Changing Fences for Vital scan
        rc = fapiGetCfamRegister(i_target, CFAM_FSI_GP3_0x00002812, fsi_data);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: fapiGetCfamRegister error (CFAM_FSI_GP3_0x00002812)");
            break;
        }
        
        rc_ecmd |= fsi_data.clearBit(23);
        rc_ecmd |= fsi_data.setBit(24);
        rc_ecmd |= fsi_data.setBit(25);
        rc_ecmd |= fsi_data.setBit(26);
        rc_ecmd |= fsi_data.clearBit(27);
        if (rc_ecmd)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: Error 0x%x setting up FSI GP3 data buffer",
                     rc_ecmd);
            rc.setEcmdError(rc_ecmd);
            break;
        }
        
        rc = fapiPutCfamRegister(i_target, CFAM_FSI_GP3_0x00002812, fsi_data);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: fapiPutCfamRegister error (CFAM_FSI_GP3_0x00002812)");
            break;
        }
        
        rc = fapiGetCfamRegister(i_target, CFAM_FSI_GP3_MIRROR_0x0000281B, fsi_data);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: fapiGetCfamRegister error (CFAM_FSI_GP3_MIRROR_0x0000281B)");
            break;
        }
        
        rc_ecmd |= fsi_data.setBit(16);
        if (rc_ecmd)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: Error 0x%x setting up FSI GP3 MIRROR data buffer",
                     rc_ecmd);
            rc.setEcmdError(rc_ecmd);
            break;
        }
        
        rc = fapiPutCfamRegister(i_target, CFAM_FSI_GP3_MIRROR_0x0000281B, fsi_data);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: fapiPutCfamRegister error (CFAM_FSI_GP3_MIRROR_0x0000281B)");
            break;
        }
        
        rc = fapiGetCfamRegister(i_target, CFAM_FSI_GP3_MIRROR_0x0000281B, fsi_data);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: fapiGetCfamRegister error (CFAM_FSI_GP3_MIRROR_0x0000281B)");
            break;
        }
        
        rc_ecmd |= fsi_data.setBit(26);
        if (rc_ecmd)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: Error 0x%x setting up FSI GP3 MIRROR data buffer",
                     rc_ecmd);
            rc.setEcmdError(rc_ecmd);
            break;
        }
        
        rc = fapiPutCfamRegister(i_target, CFAM_FSI_GP3_MIRROR_0x0000281B, fsi_data);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: fapiPutCfamRegister error (CFAM_FSI_GP3_MIRROR_0x0000281B)");
            break;
        }

        // obtain chip type/EC
        rc = FAPI_ATTR_GET_PRIVILEGED(ATTR_NAME, &i_target, chip_type);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: Error from FAPI_ATTR_GET_PRIVILEGED (ATTR_NAME)");
            break;
        }

        rc = FAPI_ATTR_GET_PRIVILEGED(ATTR_EC, &i_target, dd_level);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: Error from FAPI_ATTR_GET_PRIVILEGED (ATTR_EC)");
            break;
        }
        // configure ring/spy data buffers & spy extraction offsets based on CT/EC
        if ((chip_type == fapi::ENUM_ATTR_NAME_MURANO) && (dd_level < 0x20))
        {
            rc_ecmd |= ring_data.setBitLength(PERV_VITL_CHAIN_LENGTH_MDD1);
            rc_ecmd |= spy_data.setBitLength(TP_VITL_SPY_LENGTH_MDD1);
            spy_offsets.assign(TP_VITL_SPY_OFFSETS_MDD1, TP_VITL_SPY_OFFSETS_MDD1 + (sizeof(TP_VITL_SPY_OFFSETS_MDD1) / sizeof(TP_VITL_SPY_OFFSETS_MDD1[0])));
        }
        else if ((chip_type == fapi::ENUM_ATTR_NAME_MURANO) && (dd_level >= 0x20))
        {
            rc_ecmd |= ring_data.setBitLength(PERV_VITL_CHAIN_LENGTH_MDD2);
            rc_ecmd |= spy_data.setBitLength(TP_VITL_SPY_LENGTH_MDD2);
            spy_offsets.assign(TP_VITL_SPY_OFFSETS_MDD2, TP_VITL_SPY_OFFSETS_MDD2 + (sizeof(TP_VITL_SPY_OFFSETS_MDD2) / sizeof(TP_VITL_SPY_OFFSETS_MDD2[0])));
        }
        else if ((chip_type == fapi::ENUM_ATTR_NAME_VENICE) ||
                 (chip_type == fapi::ENUM_ATTR_NAME_NAPLES))
        {
            rc_ecmd |= ring_data.setBitLength(PERV_VITL_CHAIN_LENGTH_VN);
            rc_ecmd |= spy_data.setBitLength(TP_VITL_SPY_LENGTH_VN);
            spy_offsets.assign(TP_VITL_SPY_OFFSETS_VN, TP_VITL_SPY_OFFSETS_VN + (sizeof(TP_VITL_SPY_OFFSETS_VN) / sizeof(TP_VITL_SPY_OFFSETS_VN[0])));
        }
        else
        {
            FAPI_ERR("proc_tp_collect_dbg_data: Unsupported CT/EC combination!");
            const uint8_t CT = chip_type;
            const uint8_t EC = dd_level;
            FAPI_SET_HWP_ERROR(rc, RC_TP_COLLECT_DBG_DATA_UNSUPPORTED_CHIP);
            break;
        }
        if (rc_ecmd)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: Error 0x%x sizing FFDC data buffers",
                     rc_ecmd);
            rc.setEcmdError(rc_ecmd);
            break;
        }
        
        // collect data from ring
        rc = fapiGetRing(i_target, PERV_VITL_CHAIN_RING_ADDRESS, ring_data);
        if (rc)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: Error from fapiGetRing (PERV_VITL_CHAIN)");
            break;
        }

        // extract spy data from ring image
        uint32_t spy_offset_curr = 0;
        for (std::vector<std::pair<uint32_t, uint32_t> >::const_iterator offset = spy_offsets.begin();
             offset != spy_offsets.end();
             offset++)
        {
            uint32_t chunk_size = (offset->second - offset->first + 1);
            rc_ecmd |= spy_data.insert(ring_data,
                                       spy_offset_curr,
                                       chunk_size,
                                       offset->first);
            spy_offset_curr += chunk_size;
        }

        if (rc_ecmd)
        {
            FAPI_ERR("proc_tp_collect_dbg_data: Error 0x%x forming FFDC spy data buffer",
                     rc_ecmd);
            rc.setEcmdError(rc_ecmd);
            break;
        }

        ecmdDataBufferBase & VITL_DATA = spy_data;
        FAPI_ADD_INFO_TO_HWP_ERROR(o_rc, RC_TP_COLLECT_DBG_DATA);

    } while(0);

    // mark HWP exit
    FAPI_INF("proc_tp_collect_dbg_data: End");
    return rc;
}
// HWP entry point, comments in header
fapi::ReturnCode proc_chiplet_scominit(const fapi::Target & i_target)
{
    fapi::ReturnCode rc;
    uint32_t rc_ecmd = 0;

    fapi::TargetType target_type;
    std::vector<fapi::Target> initfile_targets;
    std::vector<fapi::Target> ex_targets;
    std::vector<fapi::Target> mcs_targets;
    uint8_t nx_enabled;
    uint8_t mcs_pos;
    uint8_t ex_pos;
    uint8_t num_ex_targets;
    uint8_t master_mcs_pos = 0xFF;
    fapi::Target master_mcs;
    uint8_t enable_xbus_resonant_clocking = 0x0;
    uint8_t i2c_slave_address = 0x0;
    uint8_t dual_capp_present = 0x0;

    ecmdDataBufferBase data(64);
    ecmdDataBufferBase cfam_data(32);
    ecmdDataBufferBase mask(64);

    bool               is_master = false;

    // mark HWP entry
    FAPI_INF("proc_chiplet_scominit: Start");

    do
    {
        rc = proc_check_master_sbe_seeprom(i_target, is_master);
        if (!rc.ok())
        {
            FAPI_ERR("proc_cen_ref_clk_enable: Error from proc_check_master_sbe_seeprom");
            break;
        }

        // obtain target type to determine which initfile(s) to execute
        target_type = i_target.getType();

        // chip level target
        if (target_type == fapi::TARGET_TYPE_PROC_CHIP)
        {
            // execute FBC SCOM initfile
            initfile_targets.push_back(i_target);
            FAPI_INF("proc_chiplet_scominit: Executing %s on %s",
                     PROC_CHIPLET_SCOMINIT_FBC_IF, i_target.toEcmdString());
            FAPI_EXEC_HWP(
                rc,
                fapiHwpExecInitFile,
                initfile_targets,
                PROC_CHIPLET_SCOMINIT_FBC_IF);
            if (!rc.ok())
            {
                FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s",
                         PROC_CHIPLET_SCOMINIT_FBC_IF,
                         i_target.toEcmdString());
                break;
            }

            // execute PSI SCOM initfile
            FAPI_INF("proc_chiplet_scominit: Executing %s on %s",
                     PROC_CHIPLET_SCOMINIT_PSI_IF, i_target.toEcmdString());
            FAPI_EXEC_HWP(
                rc,
                fapiHwpExecInitFile,
                initfile_targets,
                PROC_CHIPLET_SCOMINIT_PSI_IF);
            if (!rc.ok())
            {
                FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s",
                         PROC_CHIPLET_SCOMINIT_PSI_IF,
                         i_target.toEcmdString());
                break;
            }

            // execute TP bridge SCOM initfile
            FAPI_INF("proc_chiplet_scominit: Executing %s on %s",
                     PROC_CHIPLET_SCOMINIT_TPBRIDGE_IF, i_target.toEcmdString());
            FAPI_EXEC_HWP(
                rc,
                fapiHwpExecInitFile,
                initfile_targets,
                PROC_CHIPLET_SCOMINIT_TPBRIDGE_IF);
            if (!rc.ok())
            {
                FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s",
                         PROC_CHIPLET_SCOMINIT_TPBRIDGE_IF,
                         i_target.toEcmdString());
                break;
            }

            // query NX partial good attribute
            rc = FAPI_ATTR_GET(ATTR_PROC_NX_ENABLE,
                               &i_target,
                               nx_enabled);
            if (!rc.ok())
            {
                FAPI_ERR("proc_chiplet_scominit: Error querying ATTR_PROC_NX_ENABLE");
                break;
            }

            // apply NX/AS SCOM initfiles only if partial good attribute is set
            if (nx_enabled == fapi::ENUM_ATTR_PROC_NX_ENABLE_ENABLE)
            {
                // execute NX SCOM initfile
                FAPI_INF("proc_chiplet_scominit: Executing %s on %s",
                         PROC_CHIPLET_SCOMINIT_NX_IF, i_target.toEcmdString());
                FAPI_EXEC_HWP(
                    rc,
                    fapiHwpExecInitFile,
                    initfile_targets,
                    PROC_CHIPLET_SCOMINIT_NX_IF);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s",
                             PROC_CHIPLET_SCOMINIT_NX_IF,
                             i_target.toEcmdString());
                    break;
                }

                // execute CXA SCOM initfile
                FAPI_INF("proc_chiplet_scominit: Executing %s on %s",
                         PROC_CHIPLET_SCOMINIT_CXA_IF, i_target.toEcmdString());
                FAPI_EXEC_HWP(
                    rc,
                    fapiHwpExecInitFile,
                    initfile_targets,
                    PROC_CHIPLET_SCOMINIT_CXA_IF);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s",
                             PROC_CHIPLET_SCOMINIT_CXA_IF,
                             i_target.toEcmdString());
                    break;
                }

                // configure CXA APC master LCO settings
                rc = fapiGetChildChiplets(i_target,
                                          fapi::TARGET_TYPE_EX_CHIPLET,
                                          ex_targets,
                                          fapi::TARGET_STATE_FUNCTIONAL);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: Error from fapiGetChildChiplets (EX) on %s",
                             i_target.toEcmdString());
                    break;
                }

                // form valid LCO target list
                for (std::vector<fapi::Target>::iterator i = ex_targets.begin();
                     i != ex_targets.end();
                     i++)
                {
                    // determine EX chiplet number
                    rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &(*i), ex_pos);

                    if (!rc.ok())
                    {
                        FAPI_ERR("proc_chiplet_scominit: Error from FAPI_ATTR_GET (ATTR_CHIP_UNIT_POS) on %s",
                                 i->toEcmdString());
                        break;
                    }

                    rc_ecmd |= data.setBit(ex_pos-((ex_pos < 8)?(1):(3)));
                }
                if (!rc.ok())
                {
                    break;
                }

                num_ex_targets = ex_targets.size();
                rc_ecmd |= data.insertFromRight(
                    num_ex_targets,
                    CAPP_APC_MASTER_LCO_TARGET_MIN_START_BIT,
                    (CAPP_APC_MASTER_LCO_TARGET_MIN_END_BIT-
                     CAPP_APC_MASTER_LCO_TARGET_MIN_START_BIT+1));

                if (rc_ecmd)
                {
                    FAPI_ERR("proc_chiplet_scominit: Error 0x%x setting APC Master LCO Target register data buffer",
                             rc_ecmd);
                    rc.setEcmdError(rc_ecmd);
                    break;
                }

                rc = fapiPutScom(i_target,
                                 CAPP_APC_MASTER_LCO_TARGET_0x02013021,
                                 data);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (CAPP_APC_MASTER_LCO_TARGET_0x02013021) on %s",
                             i_target.toEcmdString());
                    break;
                }

                // get dual CAPP presence attribute
                FAPI_DBG("proc_chiplet_scominit: Querying dual CAPP feature attribute");
                rc = FAPI_ATTR_GET(ATTR_CHIP_EC_FEATURE_DUAL_CAPP_PRESENT,
                                   &i_target,
                                   dual_capp_present);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: Error querying ATTR_CHIP_EC_FEATURE_DUAL_CAPP_PRESENT");
                    break;
                }
                
                if (dual_capp_present != 0)
                {
                    rc = fapiPutScom(i_target,
                                     CAPP1_APC_MASTER_LCO_TARGET_0x020131A1,
                                     data);
                    if (!rc.ok())
                    {
                        FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (CAPP1_APC_MASTER_LCO_TARGET_0x020131A1) on %s",
                                 i_target.toEcmdString());
                        break;
                    }
                }

                // execute AS SCOM initfile
                FAPI_INF("proc_chiplet_scominit: Executing %s on %s",
                         PROC_CHIPLET_SCOMINIT_AS_IF, i_target.toEcmdString());
                FAPI_EXEC_HWP(
                    rc,
                    fapiHwpExecInitFile,
                    initfile_targets,
                    PROC_CHIPLET_SCOMINIT_AS_IF);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s",
                             PROC_CHIPLET_SCOMINIT_AS_IF,
                             i_target.toEcmdString());
                    break;
                }
            }
            else
            {
                FAPI_DBG("proc_chiplet_scominit: Skipping execution of %s/%s/%s (partial good)",
                         PROC_CHIPLET_SCOMINIT_NX_IF, PROC_CHIPLET_SCOMINIT_CXA_IF, PROC_CHIPLET_SCOMINIT_AS_IF);
            }

            // conditionally enable I2C Slave
            rc = FAPI_ATTR_GET(ATTR_I2C_SLAVE_ADDRESS,
                               &i_target,
                               i2c_slave_address);
            if (!rc.ok())
            {
                FAPI_ERR("proc_chiplet_scominit: Error querying ATTR_I2C_SLAVE_ADDRESS on %s",
                         i_target.toEcmdString());
                break;
            }
            rc = fapiGetScom(i_target,
                             I2C_SLAVE_CONFIG_REG_0x000D0000,
                             data);
            if (!rc.ok())
            {
                FAPI_ERR("proc_chiplet_scominit: fapiGetScom error (I2C_SLAVE_CONFIG_REG_0x000D0000) on %s",
                         i_target.toEcmdString());
                break;
            }
            if (i2c_slave_address)
            {
                FAPI_DBG("proc_chiplet_scominit: I2C Slave enabled (%s) address = %d",
                     i_target.toEcmdString(),i2c_slave_address);

                //set I2C address
                rc_ecmd |= data.insert(i2c_slave_address,0,7);

                // disable error state.  when this is enabled and there
                // is an error from I2CS it locks up the I2CS and no
                // more operations are allowed unless cleared
                // through FSI.  Not good for a FSPless system.
                rc_ecmd |= data.clearBit(23);

                // enable I2C interface
                rc_ecmd |= data.setBit(21);

            }
            else
            {
                FAPI_DBG("proc_chiplet_scominit: I2C Slave disabled (%s)",
                     i_target.toEcmdString());

                // disable I2C interface when attribute = 0x0
                rc_ecmd |= data.clearBit(21);
            }

            if (rc_ecmd)
            {
                FAPI_ERR("proc_chiplet_scominit: Error 0x%x setting I2C Slave register data buffer",
                         rc_ecmd);
                rc.setEcmdError(rc_ecmd);
                break;
            }

            rc = fapiPutScom(i_target,
                             I2C_SLAVE_CONFIG_REG_0x000D0000,
                             data);
            if (!rc.ok())
            {
                FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (I2C_SLAVE_CONFIG_REG_0x000D0000) on %s",
                         i_target.toEcmdString());
                break;
            }

            // conditionally enable resonant clocking for XBUS
            rc = FAPI_ATTR_GET(ATTR_CHIP_EC_FEATURE_XBUS_RESONANT_CLK_VALID,
                               &i_target,
                               enable_xbus_resonant_clocking);
            if (!rc.ok())
            {
                FAPI_ERR("proc_chiplet_scominit: Error querying ATTR_CHIP_EC_FEATURE_XBUS_RESONANT_CLK_VALID on %s",
                         i_target.toEcmdString());
                break;
            }

            if (enable_xbus_resonant_clocking)
            {
                FAPI_DBG("proc_chiplet_scominit: Enabling XBUS resonant clocking");
                rc = fapiGetScom(i_target,
                                 MBOX_FSIGP6_0x00050015,
                                 data);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: fapiGetScom error (MBOX_FSIGP6_0x00050015) on %s",
                             i_target.toEcmdString());
                    break;
                }

                rc_ecmd |= data.insertFromRight(
                    XBUS_RESONANT_CLOCK_CONFIG,
                    MBOX_FSIGP6_XBUS_RESONANT_CLOCK_CONFIG_START_BIT,
                    (MBOX_FSIGP6_XBUS_RESONANT_CLOCK_CONFIG_END_BIT-
                     MBOX_FSIGP6_XBUS_RESONANT_CLOCK_CONFIG_START_BIT+1));

                if (rc_ecmd)
                {
                    FAPI_ERR("proc_chiplet_scominit: Error 0x%x setting FSI GP6 register data buffer",
                             rc_ecmd);
                    rc.setEcmdError(rc_ecmd);
                    break;
                }

                if (is_master) 
                {
                    rc = fapiPutScom(i_target,
                                 MBOX_FSIGP6_0x00050015,
                                 data);
                    if (!rc.ok())
                    {
                        FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (MBOX_FSIGP6_0x00050015) on %s",
                             i_target.toEcmdString());
                        break;
                    }
                }
                else 
                {
                    cfam_data.insert(data, 0, 32, 0);
                    rc = fapiPutCfamRegister(i_target, CFAM_FSI_GP6_0x00002815, cfam_data);
                    if (rc)
                    {
                        FAPI_ERR("proc_cen_ref_clk_enable: fapiPutCfamRegister error (CFAM_FSI_GP8_0x00001017)");
                        break;
                    }
                }
            }

            // execute A/X/PCI/DMI FIR init SCOM initfile
            FAPI_INF("proc_chiplet_scominit: Executing %s on %s",
                     PROC_CHIPLET_SCOMINIT_A_X_PCI_DMI_IF, i_target.toEcmdString());
            FAPI_EXEC_HWP(
                rc,
                fapiHwpExecInitFile,
                initfile_targets,
                PROC_CHIPLET_SCOMINIT_A_X_PCI_DMI_IF);
            if (!rc.ok())
            {
                FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s",
                         PROC_CHIPLET_SCOMINIT_A_X_PCI_DMI_IF,
                         i_target.toEcmdString());
                break;
            }

            // execute NV scominit file
            uint8_t exist_NV = 0x00;
            rc = FAPI_ATTR_GET(ATTR_CHIP_EC_FEATURE_NV_PRESENT, &i_target, exist_NV);
            if (!rc.ok())
            {
                FAPI_ERR("proc_chiplet_scominit: Error getting attribute value ATTR_CHIP_EC_FEATURE_NV_PRESENT");
                break;
            }
            if (exist_NV)
            {
                FAPI_INF("proc_chiplet_scominit: Executing  %s on %s",
                         PROC_CHIPLET_SCOMINIT_NPU_IF, i_target.toEcmdString());
                FAPI_EXEC_HWP(
                        rc,
                        fapiHwpExecInitFile,
                        initfile_targets,
                        PROC_CHIPLET_SCOMINIT_NPU_IF);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s",
                             PROC_CHIPLET_SCOMINIT_NPU_IF,
                             i_target.toEcmdString());
                    break;
                }

                // cleanup FIR bit (NPU FIR bit 27) caused by NDL/NTL parity error
                rc_ecmd = data.flushTo1();
                rc_ecmd = data.clearBit(NPU_FIR_NTL_DL2TL_PARITY_ERR_BIT);
                if (rc_ecmd)
                {
                    FAPI_ERR("proc_chiplet_scominit: Error 0x%Xforming NPU FIR cleanup data buffer",
                  	   rc_ecmd);
                    rc.setEcmdError(rc_ecmd);
                    break;
                }
                rc = fapiPutScom(i_target, NPU_FIR_AND_0x08013D81, data);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (NPU_FIR_AND_0x08013D81) on %s",
                             i_target.toEcmdString());
                    break;
                }
                rc = fapiPutScom(i_target, NPU_FIR_MASK_AND_0x08013D84, data);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: fapiPutScom error (NPU_FIR_MASK_AND_0x08013D84) on %s",
                             i_target.toEcmdString());
                    break;
                }
            }
            else
            {
                FAPI_INF("proc_chiplet_scominit: NV link logic not present, scom initfile processing skipped");
            }

            // determine set of functional MCS chiplets
            rc = fapiGetChildChiplets(i_target,
                                      fapi::TARGET_TYPE_MCS_CHIPLET,
                                      mcs_targets,
                                      fapi::TARGET_STATE_FUNCTIONAL);
            if (!rc.ok())
            {
                FAPI_ERR("proc_chiplet_scominit: Error from fapiGetChildChiplets (MCS) on %s",
                         i_target.toEcmdString());
                break;
            }

            // apply MCS SCOM initfile only for functional chiplets
            for (std::vector<fapi::Target>::iterator i = mcs_targets.begin();
                 (i != mcs_targets.end()) && rc.ok();
                 i++)
            {
                // execute MCS SCOM initfile
                initfile_targets.clear();
                initfile_targets.push_back(*i);
                initfile_targets.push_back(i_target);
                FAPI_INF("proc_chiplet_scominit: Executing %s on %s",
                         PROC_CHIPLET_SCOMINIT_MCS_IF, i->toEcmdString());
                FAPI_EXEC_HWP(
                    rc,
                    fapiHwpExecInitFile,
                    initfile_targets,
                    PROC_CHIPLET_SCOMINIT_MCS_IF);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: Error from fapiHwpExecInitfile executing %s on %s",
                             PROC_CHIPLET_SCOMINIT_MCS_IF,
                             i->toEcmdString());
                    break;
                }

                // determine MCS position
                rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &(*i), mcs_pos);

                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: Error from FAPI_ATTR_GET (ATTR_CHIP_UNIT_POS) on %s",
                             i->toEcmdString());
                    break;
                }

                if (mcs_pos < master_mcs_pos)
                {
                    fapi::Target cen_target_unused;
                    rc = fapiGetOtherSideOfMemChannel(*i,
                                                      cen_target_unused,
                                                      fapi::TARGET_STATE_FUNCTIONAL);
                    // use return code only to indicate presence of connected Centaur,
                    // do not propogate/emit error if not connected
                    if (rc.ok())
                    {
                        FAPI_DBG("Updating master_mcs_pos to %d", mcs_pos);
                        FAPI_DBG("  Target: %s", cen_target_unused.toEcmdString());
                        master_mcs = *i;
                        master_mcs_pos = mcs_pos;
                    }
                    else
                    {
                        rc = fapi::FAPI_RC_SUCCESS;
                    }
                }

            }
            if (!rc.ok())
            {
                break;
            }

            if (master_mcs.getType() == fapi::TARGET_TYPE_MCS_CHIPLET)
            {
                // set MCMODE0Q_ENABLE_CENTAUR_SYNC on first target only
                // (this bit is required to be set on at most one MCS/chip)
                rc_ecmd |= data.flushTo0();
                rc_ecmd |= data.setBit(MCSMODE0_EN_CENTAUR_SYNC_BIT);
                rc_ecmd |= mask.setBit(MCSMODE0_EN_CENTAUR_SYNC_BIT);

                // check buffer manipulation return codes
                if (rc_ecmd)
                {
                    FAPI_ERR("proc_chiplet_scominit: Error 0x%X setting up MCSMODE0 data buffer",
                             rc_ecmd);
                    rc.setEcmdError(rc_ecmd);
                    break;
                }

                // write register with updated content
                rc = fapiPutScomUnderMask(master_mcs,
                                          MCS_MCSMODE0_0x02011807,
                                          data,
                                          mask);
                if (!rc.ok())
                {
                    FAPI_ERR("proc_chiplet_scominit: fapiPutScomUnderMask error (MCS_MCSMODE0_0x02011807) on %s",
                             master_mcs.toEcmdString());
                    break;
                }

            }
        }
        // unsupported target type
        else
        {
            FAPI_ERR("proc_chiplet_scominit: Unsupported target type");
            const fapi::Target & TARGET = i_target;
            FAPI_SET_HWP_ERROR(rc, RC_PROC_CHIPLET_SCOMINIT_INVALID_TARGET);
            break;
        }
    } while(0);

    // mark HWP exit
    FAPI_INF("proc_chiplet_scominit: End");
    return rc;
}
//------------------------------------------------------------------------------
// function:
//      Stop SBE runtime scan service
//
// parameters: i_target => chip target
// returns: FAPI_RC_SUCCESS if operation was successful, else error
//------------------------------------------------------------------------------
fapi::ReturnCode proc_stop_sbe_scan_service(
    const fapi::Target& i_target,
    const void* i_pSEEPROM)
{
    // return codes
    fapi::ReturnCode rc;
    uint32_t rc_ecmd = 0;

    // track if procedure has cleared I2C master bus fence
    bool i2cm_bus_fence_cleared = false;

    // mark function entry
    FAPI_DBG("Start");

    do
    {
        // check SBE progress
        bool sbe_running = true;
        size_t loop_time = 0;
        uint8_t halt_code = 0;
        uint16_t istep_num = 0;
        uint8_t substep_num = 0;
        bool scan_service_loop_reached = false;

        // retrieve status
        rc = proc_sbe_utils_check_status(
            i_target,
            sbe_running,
            halt_code,
            istep_num,
            substep_num);
        if (!rc.ok())
        {
            FAPI_ERR("Error from proc_check_sbe_state_check_status");
            break;
        }

        // get HB->SBE request mailbox, check that it is clear
        ecmdDataBufferBase mbox_data(64);
        bool sbe_ready = false;
        rc = fapiGetScom(i_target, MBOX_SCRATCH_REG0_0x00050038, mbox_data);
        if (!rc.ok())
        {
            FAPI_ERR("Scom error reading SBE MBOX0 Register");
            break;
        }
        sbe_ready = (mbox_data.getDoubleWord(0) == 0);

        scan_service_loop_reached =
            sbe_running &&
            sbe_ready &&
            !halt_code &&
            (istep_num == PROC_SBE_SCAN_SERVICE_ISTEP_NUM) &&
            (substep_num == SUBSTEP_SBE_READY);

        FAPI_INF("SBE is running [%d], loop time [%zd], scan service loop reached [%d]",
                 sbe_running, loop_time, scan_service_loop_reached);

        if (!sbe_running)
        {
            FAPI_INF("SBE is stopped, exiting!");
            break;
        }
        else if (scan_service_loop_reached)
        {
            // format stop request
            rc_ecmd |= mbox_data.setBit(MBOX0_REQUEST_VALID_BIT);
            rc_ecmd |= mbox_data.insertFromRight(MBOX0_HALT_PATTERN,
                                                 MBOX0_HALT_PATTERN_START_BIT,
                                                 (MBOX0_HALT_PATTERN_END_BIT-
                                                  MBOX0_HALT_PATTERN_START_BIT)+1);
            if (rc_ecmd)
            {
                FAPI_ERR("Error 0x%x setting up SBE MBOX0 data buffer.", rc_ecmd);
                rc.setEcmdError(rc_ecmd);
                break;
            }

            // submit stop request to SBE
            FAPI_DBG("Submitting stop request to SBE");
            rc = fapiPutScom(i_target, MBOX_SCRATCH_REG0_0x00050038, mbox_data);
            if (!rc.ok())
            {
                FAPI_ERR("Error writing SBE MBOX0 Register");
                break;
            }

            // pause to allow request to be processed
            uint32_t loop_num = 0;
            while (sbe_running && (loop_num < SBE_HALT_POLL_MAX_LOOPS))
            {
                loop_num++;
                rc = fapiDelay(SBE_HALT_POLL_DELAY_HW, SBE_HALT_POLL_DELAY_SIM);
                if (!rc.ok())
                {
                    FAPI_ERR("Error from fapiDelay");
                    break;
                }

                // retrieve status
                rc = proc_sbe_utils_check_status(
                    i_target,
                    sbe_running,
                    halt_code,
                    istep_num,
                    substep_num);
                if (!rc.ok())
                {
                    FAPI_ERR("Error from proc_check_sbe_state_check_status");
                    break;
                }
            }
            if (rc)
            {
                break;
            }
            if (sbe_running)
            {
                FAPI_ERR("SBE is STILL running!");
                const fapi::Target & TARGET = i_target;
                FAPI_SET_HWP_ERROR(rc, RC_PROC_STOP_SBE_SCAN_SERVICE_SBE_NOT_STOPPED);
                break;
            }

            // before analysis proceeds, make sure that I2C master bus fence is cleared
            FAPI_EXEC_HWP(rc, proc_reset_i2cm_bus_fence, i_target);
            if (!rc.ok())
            {
                FAPI_ERR("Error from proc_reset_i2cm_bus_fence");
                break;
            }
            // mark that fence has been cleared
            i2cm_bus_fence_cleared = true;

            //  ensure correct halt code is captured
            rc = proc_sbe_utils_check_status(
                i_target,
                sbe_running,
                halt_code,
                istep_num,
                substep_num);
            if (!rc.ok())
            {
                FAPI_ERR("Error from proc_check_sbe_state_check_status");
                break;
            }

            // confirm that expected halt point was reached
            if (halt_code != SBE_EXIT_SUCCESS_0xF)
            {
                FAPI_ERR("SBE halted with error 0x%X (istep 0x%03X, substep 0x%X)",
                         halt_code, istep_num, substep_num);
                // extract & return error code from analyzing SBE state
                FAPI_EXEC_HWP(rc, proc_extract_sbe_rc, i_target, NULL, i_pSEEPROM, SBE);
                break;
            }

            if ((istep_num != PROC_SBE_SCAN_SERVICE_ISTEP_NUM) ||
                (substep_num != SUBSTEP_HALT_SUCCESS))
            {
                FAPI_ERR("Expected SBE istep 0x%03llX, substep 0x%X but found istep 0x%03X, substep 0x%X",
                         PROC_SBE_SCAN_SERVICE_ISTEP_NUM, SUBSTEP_HALT_SUCCESS,
                         istep_num, substep_num);
                const fapi::Target & TARGET = i_target;
                const uint32_t & ISTEP_NUM = istep_num;
                const uint32_t & SUBSTEP_NUM = substep_num;
                FAPI_SET_HWP_ERROR(rc, RC_PROC_STOP_SBE_SCAN_SERVICE_SBE_BAD_HALT);
                break;
            }

            // Reset the SBE so it can be used for MPIPL if needed
            ecmdDataBufferBase sbe_reset_data(64);
            rc = fapiPutScom(i_target, PORE_SBE_RESET_0x000E0002, sbe_reset_data);
            if (!rc.ok())
            {
                FAPI_ERR("Scom error resetting SBE\n");
                break;
            }
        }
        // error
        else
        {
            FAPI_ERR("SBE did not reach acceptable final state!");
            const fapi::Target & TARGET = i_target;
            const bool & SBE_RUNNING = sbe_running;
            const uint8_t & HALT_CODE = halt_code;
            const uint16_t & ISTEP_NUM = istep_num;
            const uint8_t & SUBSTEP_NUM = substep_num;
            FAPI_SET_HWP_ERROR(rc, RC_PROC_STOP_SBE_SCAN_SERVICE_UNEXPECTED_FINAL_STATE);
            break;
        }

    } while(0);

    // if an error occurred prior to the I2C master bus fence
    // being cleared, attempt to clear it prior to exit
    if (!rc.ok() && !i2cm_bus_fence_cleared)
    {
        // discard rc, return that of original fail
        fapi::ReturnCode rc_unused;
        FAPI_EXEC_HWP(rc_unused, proc_reset_i2cm_bus_fence, i_target);
    }

    // mark function entry
    FAPI_DBG("End");
    return rc;
}