//------------------------------------------------------------------------------ // 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; }
/** * @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; }
//------------------------------------------------------------------------------ // 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; }
/** * @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; }
/** * @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; }
/** * @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; }
//----------------------------------------------------------------------------- // 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; }
/** * @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; }
//----------------------------------------------------------------------------- // 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; }
// 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; }
//------------------------------------------------------------------------------ // 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; }
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; }
//------------------------------------------------------------------------------ // 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; }
//------------------------------------------------------------------------------ // 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; }
//------------------------------------------------------------------------------ // 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; }