//------------------------------------------------------------------------------ // function: utility subroutine which writes AND/OR mask register to // set/clear desired bits // parameters: i_target => target // i_active_mask => bit mask defining active bits to act on // i_set_not_clear => define desired operation // (true=set, false=clear) // i_and_mask_addr => SCOM address for AND mask register // i_or_mask_addr => SCOM address for OR mask register // returns: FAPI_RC_SUCCESS if operation was successful, else error //------------------------------------------------------------------------------ fapi::ReturnCode proc_fab_iovalid_write_active_mask( const fapi::Target& i_target, ecmdDataBufferBase& i_active_mask, bool i_set_not_clear, const uint32_t& i_and_mask_addr, const uint32_t& i_or_mask_addr) { // data buffer to hold final bit mask ecmdDataBufferBase mask(64); // return codes uint32_t rc_ecmd = 0; fapi::ReturnCode rc; // mark function entry FAPI_DBG("proc_fab_iovalid_write_active_mask: Start"); do { // copy input mask rc_ecmd = i_active_mask.copy(mask); // form final mask based on desired operation (set/clear) if (!i_set_not_clear) { FAPI_DBG("proc_fab_iovalid_write_active_mask: Inverting active mask"); rc_ecmd |= mask.invert(); } // check return code from buffer manipulation operations if (rc_ecmd) { FAPI_ERR("proc_fab_iovalid_write_active_mask: Error 0x%x setting up active mask data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } // write register (use OR mask address for set operation, // AND mask address for clear operation) rc = fapiPutScom(i_target, i_set_not_clear?i_or_mask_addr:i_and_mask_addr, mask); if (!rc.ok()) { FAPI_ERR("proc_fab_iovalid_write_active_mask: fapiPutScom error (0x%08X)", i_set_not_clear?i_or_mask_addr:i_and_mask_addr); break; } } while (0); // mark function exit FAPI_DBG("proc_fab_iovalid_write_active_mask: End"); return 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; }
// parameters: // 'i_target' is chip target // // returns: // FAPI_RC_SUCCESS (success, EX chiplets entered fast winkle) // // getscom/putscom/getattribute fapi errors // fapi error assigned from eCMD function failure // //------------------------------------------------------------------------------ fapi::ReturnCode proc_mpipl_ex_cleanup(const fapi::Target & i_target) { const char *procedureName = "proc_mpipl_ex_cleanup"; fapi::ReturnCode rc; //fapi return code uint32_t rc_ecmd = 0; //ecmd return code value ecmdDataBufferBase fsi_data(64); //64-bit data buffer uint8_t attr_chip_unit_pos; //EX chiplet's unit offset within chip with respect to similar EX units const uint64_t EX_OFFSET_MULT = 0x01000000; //Multiplier used to calculate offset for respective EX chiplet uint64_t address; // Varible for computed addresses uint64_t offset; char reg_name[32]; // Character array for register names // Relevant PMGP0 bits // const uint32_t PM_DISABLE = 0; const uint32_t BLOCK_REG_WKUP_SOURCE = 53; // Relevant PMGP1 bits const uint32_t WINKLE_POWER_OFF_SEL = 5; std::vector<fapi::Target> v_ex_chiplets; //Vector of EX chiplets do { //Entering fapi function FAPI_INF("Entering %s", procedureName); //Get vector of EX chiplets rc = fapiGetChildChiplets( i_target, fapi::TARGET_TYPE_EX_CHIPLET, v_ex_chiplets, fapi::TARGET_STATE_FUNCTIONAL); if (rc) { FAPI_ERR("%s: fapiGetChildChiplets error", procedureName); break; } FAPI_INF("Processing target %s", i_target.toEcmdString()); //Parse thru EX chiplets and prepare fast-winkled cores for deep operations //Loop thru EX chiplets in vector for (uint32_t counter = 0; counter < v_ex_chiplets.size(); counter++) { // Get EX chiplet number rc = FAPI_ATTR_GET( ATTR_CHIP_UNIT_POS, &(v_ex_chiplets[counter]), attr_chip_unit_pos); if (rc) { FAPI_ERR("%s: fapiGetAttribute error (ATTR_CHIP_UNIT_POS)", procedureName); break; } FAPI_INF("EX chiplet pos = 0x%02X", attr_chip_unit_pos); // Calculate the address offset based on chiplet number offset = EX_OFFSET_MULT * attr_chip_unit_pos; // ----------------------------------------------------------------- FAPI_DBG("\tOriginal register contents"); address = EX_GP3_0x100F0012 + offset; strcpy(reg_name, "GP3"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); address = EX_PMGP0_0x100F0100 + offset; strcpy(reg_name, "PMGP0"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); address = EX_PMGP1_0x100F0103 + offset; strcpy(reg_name, "PMGP1"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); // ----------------------------------------------------------------- // Clean up configuration remnants of the fast-winkle configuration // that was used to flush the chiplets after checkstop. EX chiplets // will have been through SBE EX Init with certain step skippled due // to MPIPL. FAPI_INF("Re-establish Deep Winkle mode default"); address = EX_PMGP1_OR_0x100F0105 + offset; strcpy(reg_name, "PMGP1 OR"); rc_ecmd |= fsi_data.flushTo0(); rc_ecmd |= fsi_data.setBit(WINKLE_POWER_OFF_SEL); if(rc_ecmd) { FAPI_ERR("ecmdDatatBuffer error preparing %s reg (addr: 0x%08llX) with rc %x", reg_name, address, rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, address, fsi_data); if (rc) { FAPI_ERR("fapiPutScom error (addr: 0x%08llX)", address); break; } FAPI_INF("Clear block wakeup sources to PM logic. PM is NOT re-enabled"); // (eg clear Block Interrrupt Sources) address = EX_PMGP0_AND_0x100F0101 + offset; strcpy(reg_name, "PMGP0 AND"); rc_ecmd |= fsi_data.flushTo1(); // rc_ecmd |= fsi_data.clearBit(PM_DISABLE); rc_ecmd |= fsi_data.clearBit(BLOCK_REG_WKUP_SOURCE); if(rc_ecmd) { FAPI_ERR("ecmdDatatBuffer error preparing %s reg (addr: 0x%08llX)", reg_name, address); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, address, fsi_data); if (rc) { FAPI_ERR("fapiPutScom error (addr: 0x%08llX)", address); break; } // ----------------------------------------------------------------- FAPI_DBG("\tUpdated register contents"); address = EX_GP3_0x100F0012 + offset; strcpy(reg_name, "GP3"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); address = EX_PMGP0_0x100F0100 + offset; strcpy(reg_name, "PMGP0"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); address = EX_PMGP1_0x100F0103 + offset; strcpy(reg_name, "PMGP1"); rc = fapiGetScom( i_target, address, fsi_data ); if (rc) { FAPI_ERR("fapiGetScom error (addr: 0x%08llX)", address); break; } FAPI_DBG("\t%s (addr: 0x%08llX), val=0x%016llX", reg_name, address, fsi_data.getDoubleWord(0)); // ----------------------------------------------------------------- } // chiplet loop // Error exit from above loop // Not really needed as outer while(0) is next but here for consistent structure if (!rc.ok()) { break; } } while (0); //Exiting fapi function FAPI_INF("Exiting %s", procedureName); return rc; }
// HWP entry point fapi::ReturnCode proc_getecid( const fapi::Target& i_target, ecmdDataBufferBase& io_fuseString) { // return code fapi::ReturnCode rc; uint32_t rc_ecmd = 0; uint64_t attr_data[2]; // mark HWP entry FAPI_DBG("proc_getecid: Start"); io_fuseString.setBitLength(112); // sets size and zeros out buffer ecmdDataBufferBase otprom_mode_data(64); ecmdDataBufferBase ecid_data(64); do { // // clear ECC enable before reading ECID data (read-modify-write OTPROM Mode register) // rc = fapiGetScom(i_target, OTPC_M_MODE_REGISTER_0x00010008, otprom_mode_data); if (!rc.ok()) { FAPI_ERR("proc_getecid: fapiGetScom error (OTPC_M_MODE_REGISTER_0x00010008) for %s", i_target.toEcmdString()); break; } rc_ecmd |= otprom_mode_data.clearBit(OTPC_M_MODE_REGISTER_ECC_ENABLE_BIT); if (rc_ecmd) { FAPI_ERR("proc_getecid: Error 0x%X setting up OTPROM Mode register data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, OTPC_M_MODE_REGISTER_0x00010008, otprom_mode_data); if (!rc.ok()) { FAPI_ERR("proc_getecid: fapiPutScom error (OTPC_M_MODE_REGISTER_0x00010008) for %s", i_target.toEcmdString()); break; } // // extract and manipulate ECID data // rc = fapiGetScom(i_target, ECID_PART_0_0x00018000, ecid_data); if (!rc.ok()) { FAPI_ERR("proc_getecid: fapiGetScom error (ECID_PART_0_0x00018000) for %s", i_target.toEcmdString()); break; } // 0:63 become 63:0 rc_ecmd |= ecid_data.reverse(); // copy bits 0:63 from the scom into 0:63 of the fuseString/attribute data rc_ecmd |= io_fuseString.insert(ecid_data, 0, 64); attr_data[0] = ecid_data.getDoubleWord(0); if (rc_ecmd) { FAPI_ERR("proc_getecid: Error 0x%X processing ECID (part 0) data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiGetScom(i_target, ECID_PART_1_0x00018001, ecid_data); if (!rc.ok()) { FAPI_ERR("proc_getecid: fapiGetScom error (ECID_PART_1_0x00018001) for %s", i_target.toEcmdString()); break; } // 0:63 become 63:0 rc_ecmd |= ecid_data.reverse(); // copy bits 0:47 from the scom into 64:111 of the fuseString // all bits into attribute data rc_ecmd |= io_fuseString.insert(ecid_data, 64, 48); attr_data[1] = ecid_data.getDoubleWord(0); if (rc_ecmd) { FAPI_ERR("proc_getecid: Error 0x%X processing ECID (part 1) data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } // push fuse string into attribute rc = FAPI_ATTR_SET(ATTR_ECID, &i_target, attr_data); if (!rc.ok()) { FAPI_ERR("proc_getecid: Error from FAPI_ATTR_SET (ATTR_ECID) for %s (attr_data[0] = %016llX, attr_data[1] = %016llX", i_target.toEcmdString(), attr_data[0], attr_data[1]); break; } // // restore ECC enable setting // rc_ecmd |= otprom_mode_data.setBit(OTPC_M_MODE_REGISTER_ECC_ENABLE_BIT); if (rc_ecmd) { FAPI_ERR("proc_getecid: Error 0x%X setting up OTPROM Mode register data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, OTPC_M_MODE_REGISTER_0x00010008, otprom_mode_data); if (!rc.ok()) { FAPI_ERR("proc_getecid: fapiPutScom error (OTPC_M_MODE_REGISTER_0x00010008) for %s", i_target.toEcmdString()); break; } } while(0); // mark HWP exit FAPI_DBG("proc_getecid: End"); return rc; }
// 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: 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; }
//------------------------------------------------------------------------------ // 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: initialize PBCQ FIRs // clear FIR/WOF // initialize FIR action settings // reset FIR masks // parameters: i_target => processor chip target // i_num_phb => number of PHB units // returns: FAPI_RC_SUCCESS if all actions are successful, // else error //------------------------------------------------------------------------------ fapi::ReturnCode proc_pcie_config_pbcq_fir( const fapi::Target & i_target, uint8_t i_num_phb) { fapi::ReturnCode rc; uint32_t rc_ecmd = 0; ecmdDataBufferBase data(64); // mark function entry FAPI_INF("proc_pcie_config_pbcq_fir: Start"); // loop over all PHBs for (size_t i = 0; i < i_num_phb; i++) { // clear FIR rc_ecmd |= data.flushTo0(); if (rc_ecmd) { FAPI_ERR("proc_pcie_config_pbcq_fir: Error 0x%x setting up PCIE Nest FIR clear data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, PROC_PCIE_CONFIG_PCIE_NEST_FIR[i], data); if (!rc.ok()) { FAPI_ERR("proc_pcie_config_pbcq_fir: Error from fapiPutScom (PCIE%zd_FIR_0x%08X)", i, PROC_PCIE_CONFIG_PCIE_NEST_FIR[i]); break; } // clear FIR WOF rc = fapiPutScom(i_target, PROC_PCIE_CONFIG_PCIE_NEST_FIR_WOF[i], data); if (!rc.ok()) { FAPI_ERR("proc_pcie_config_pbcq_fir: Error from fapiPutScom (PCIE%zd_FIR_WOF_0x%08X)", i, PROC_PCIE_CONFIG_PCIE_NEST_FIR_WOF[i]); break; } // set action0 rc_ecmd |= data.setDoubleWord(0, PROC_PCIE_CONFIG_PCIE_NEST_FIR_ACTION0_VAL); if (rc_ecmd) { FAPI_ERR("proc_pcie_config_pbcq_fir: Error 0x%x setting up PCIE Nest FIR Action0 register data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, PROC_PCIE_CONFIG_PCIE_NEST_FIR_ACTION0[i], data); if (!rc.ok()) { FAPI_ERR("proc_pcie_config_pbcq_fir: Error from fapiPutScom (PCIE%zd_FIR_ACTION0_0x%08X)", i, PROC_PCIE_CONFIG_PCIE_NEST_FIR_ACTION0[i]); break; } // set action1 rc_ecmd |= data.setDoubleWord(0, PROC_PCIE_CONFIG_PCIE_NEST_FIR_ACTION1_VAL); if (rc_ecmd) { FAPI_ERR("proc_pcie_config_pbcq_fir: Error 0x%x setting up PCIE Nest FIR Action1 register data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, PROC_PCIE_CONFIG_PCIE_NEST_FIR_ACTION1[i], data); if (!rc.ok()) { FAPI_ERR("proc_pcie_config_pbcq_fir: Error from fapiPutScom (PCIE%zd_FIR_ACTION1_0x%08X)", i, PROC_PCIE_CONFIG_PCIE_NEST_FIR_ACTION1[i]); break; } // set action2 fapi::ATTR_CHIP_EC_FEATURE_PCI_NEST_FIR_ACTION2_PRESENT_Type action2_present = 0; rc = FAPI_ATTR_GET(ATTR_CHIP_EC_FEATURE_PCI_NEST_FIR_ACTION2_PRESENT, &i_target, action2_present); if (!rc.ok()) { FAPI_ERR("proc_pcie_config_pbcq_fir: fapiGetAttribute of ATTR_CHIP_EC_FEATURE_PCI_NEST_FIR_ACTION2_PRESENT failed"); break; } if (action2_present) { rc_ecmd |= data.setDoubleWord(0, PROC_PCIE_CONFIG_PCIE_NEST_FIR_ACTION2_VAL); if (rc_ecmd) { FAPI_ERR("proc_pcie_config_pbcq_fir: Error 0x%x setting up PCIE Nest FIR Action2 register data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, PROC_PCIE_CONFIG_PCIE_NEST_FIR_ACTION2[i], data); if (!rc.ok()) { FAPI_ERR("proc_pcie_config_pbcq_fir: Error from fapiPutScom (PCIE%zd_FIR_ACTION2_0x%08X)", i, PROC_PCIE_CONFIG_PCIE_NEST_FIR_ACTION2[i]); break; } } // set mask rc_ecmd |= data.setDoubleWord(0, PROC_PCIE_CONFIG_PCIE_NEST_FIR_MASK_VAL); if (rc_ecmd) { FAPI_ERR("proc_pcie_config_pbcq_fir: Error 0x%x setting up PCIE Nest FIR Mask register data buffer", rc_ecmd); rc.setEcmdError(rc_ecmd); break; } rc = fapiPutScom(i_target, PROC_PCIE_CONFIG_PCIE_NEST_FIR_MASK[i], data); if (!rc.ok()) { FAPI_ERR("proc_pcie_config_pbcq_fir: Error from fapiPutScom (PCIE%zd_FIR_MASK_0x%08X)", i, PROC_PCIE_CONFIG_PCIE_NEST_FIR_MASK[i]); break; } } // mark function exit FAPI_INF("proc_pcie_config_pbcq_fir: End"); 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: // 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; }