/// @brief Platform-level implementation of modifyCfamRegister() ReturnCode platModifyCfamRegister(const Target<TARGET_TYPE_ALL>& i_target, const uint32_t i_address, const buffer<uint32_t> i_data, const ChipOpModifyMode i_modifyMode) { FAPI_DBG(ENTER_MRK "platModifyCfamRegister"); ReturnCode l_rc; errlHndl_t l_err = NULL; bool l_traceit = platIsScanTraceEnabled(); const char* l_modeString = platModeString(i_modifyMode); // Grab the name of the target TARGETING::ATTR_FAPI_NAME_type l_targName = {0}; fapi2::toString(i_target, l_targName, sizeof(l_targName)); do { // Can't access cfam engine on master processor l_err = verifyCfamAccessTarget(i_target,i_address); if (l_err) { FAPI_ERR("platModifyCfamRegister: verifyCfamAccessTarget returns error!"); l_rc.setPlatDataPtr(reinterpret_cast<void *> (l_err)); break; } // Extract the component pointer TARGETING::Target* l_target = reinterpret_cast<TARGETING::Target*>(i_target.get()); // Get the chip target if l_target is not a chip TARGETING::Target* l_myChipTarget = NULL; l_err = getCfamChipTarget(l_target, l_myChipTarget); if (l_err) { FAPI_ERR("platModifyCfamRegister: getCfamChipTarget returns error!"); l_rc.setPlatDataPtr(reinterpret_cast<void *> (l_err)); break; } // Read current value // Address needs to be multiply by 4 because register addresses are word // offsets but the FSI addresses are byte offsets. // However, we need to preserve the engine's offset of 0x0C00 and 0x1000 uint64_t l_addr = ((i_address & CFAM_ADDRESS_MASK) << 2) | (i_address & CFAM_ENGINE_OFFSET); buffer<uint32_t> l_data = 0; size_t l_size = sizeof(uint32_t); l_err = deviceRead(l_myChipTarget, &l_data(), l_size, DEVICE_FSI_ADDRESS(l_addr)); if (l_err) { FAPI_ERR("platModifyCfamRegister: deviceRead returns error!"); l_rc.setPlatDataPtr(reinterpret_cast<void *> (l_err)); break; } // Applying modification platProcess32BitModifyMode(i_modifyMode, i_data, l_data); // Write back l_err = deviceWrite(l_target, &l_data(), l_size, DEVICE_FSI_ADDRESS(l_addr)); if (l_err) { FAPI_ERR("platModifyCfamRegister: deviceWrite returns error!"); l_rc.setPlatDataPtr(reinterpret_cast<void *> (l_err)); break; } } while (0); if (l_rc != fapi2::FAPI2_RC_SUCCESS) { FAPI_ERR("platModifyCfamRegister failed - Target %s, Addr %.8X", l_targName, i_address); } if( l_traceit ) { uint32_t l_data = (uint32_t)i_data; FAPI_SCAN( "TRACE : MODCFAMREG : %s : %.8X %.8X %s", l_targName, i_address, l_data, l_modeString ); } FAPI_DBG(EXIT_MRK "platModifyCfamRegister"); return l_rc; }
/// @brief Platform-level implementation called by getCfamRegister() ReturnCode platGetCfamRegister(const Target<TARGET_TYPE_ALL>& i_target, const uint32_t i_address, buffer<uint32_t>& o_data) { FAPI_DBG(ENTER_MRK "platGetCfamRegister"); ReturnCode l_rc; errlHndl_t l_err = NULL; bool l_traceit = platIsScanTraceEnabled(); // Grab the name of the target TARGETING::ATTR_FAPI_NAME_type l_targName = {0}; fapi2::toString(i_target, l_targName, sizeof(l_targName)); do { // Extract the target pointer TARGETING::Target* l_target = reinterpret_cast<TARGETING::Target*>(i_target.get()); // Get the chip target if l_target is not a chip TARGETING::Target* l_myChipTarget = NULL; l_err = getCfamChipTarget(l_target, l_myChipTarget); if (l_err) { FAPI_ERR("platGetCfamRegister: getCfamChipTarget returns error!"); FAPI_ERR("fapiGetCfamRegister failed - Target %s, Addr %.8X", l_targName, i_address); l_rc.setPlatDataPtr(reinterpret_cast<void *> (l_err)); break; } // Can't access cfam engine on master processor l_err = verifyCfamAccessTarget(i_target,i_address); if (l_err) { FAPI_ERR("platGetCfamRegister: verifyCfamAccessTarget returns error!"); l_rc.setPlatDataPtr(reinterpret_cast<void *> (l_err)); break; } // Perform CFAM read via FSI // Address needs to be multiply by 4 because register addresses are // word offsets but the FSI addresses are byte offsets. // However, we need to preserve the engine's offset in the top byte uint64_t l_addr = ((i_address & CFAM_ADDRESS_MASK) << 2) | (i_address & CFAM_ENGINE_OFFSET); size_t l_size = sizeof(uint32_t); l_err = deviceRead(l_myChipTarget, &o_data(), l_size, DEVICE_FSI_ADDRESS(l_addr)); if (l_err) { FAPI_ERR("platGetCfamRegister: deviceRead returns error!"); l_rc.setPlatDataPtr(reinterpret_cast<void *> (l_err)); break; } } while(0); if (l_rc != fapi2::FAPI2_RC_SUCCESS) { FAPI_ERR("fapiGetCfamRegister failed - Target %s, Addr %.8X", l_targName, i_address); } if( l_traceit ) { uint32_t l_data = (uint32_t)o_data; FAPI_SCAN( "TRACE : GETCFAMREG : %s : %.8X %.8X", l_targName, i_address, l_data); } FAPI_DBG(EXIT_MRK "platGetCfamRegister"); return l_rc; }
/** * @brief Common function to add callouts and FFDC and recover * from PIB errors * * @param[in] i_target SCom target * @param[in] i_errlog Error log to append to * @param[in] i_status FSI2PIB status register * @param[in] i_scomAddr Address that we failed on */ void pib_error_handler( TARGETING::Target* i_target, errlHndl_t i_errlog, uint32_t i_status, uint32_t i_scomAddr ) { //Add this target to the FFDC ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target").addToLog(i_errlog); //Look for a totally dead chip if( i_status == 0xFFFFFFFF ) { // if things are this broken then chances are there are bigger // problems, we can just make some guesses on what to call out // make code the highest since there are other issues i_errlog->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_HIGH); // callout this chip as Medium and deconfigure it i_errlog->addHwCallout( i_target, HWAS::SRCI_PRIORITY_LOW, HWAS::DELAYED_DECONFIG, HWAS::GARD_NULL ); // grab all the FFDC we can think of FSI::getFsiFFDC( FSI::FFDC_OPB_FAIL_SLAVE, i_errlog, i_target ); FSI::getFsiFFDC( FSI::FFDC_READWRITE_FAIL, i_errlog, i_target ); FSI::getFsiFFDC( FSI::FFDC_PIB_FAIL, i_errlog, i_target ); } else { //Add the callouts for the specific PCB/PIB error uint32_t pib_error = i_status >> 12; PIB::addFruCallouts( i_target, pib_error, i_scomAddr, i_errlog ); //Grab the PIB2OPB Status reg for a Resource Occupied error if( pib_error == PIB::PIB_RESOURCE_OCCUPIED ) //piberr=001 { FSI::getFsiFFDC( FSI::FFDC_PIB_FAIL, i_errlog, i_target ); } } //Recovery sequence from Markus // if SCOM fails and FSI Master displays "MasterTimeOut" // then 7,6 <covered by FSI driver> // else if SCOM fails and FSI2PIB Status shows PIB abort // then just perform unit reset (6) and wait 1 ms // else (PIB_abort='0' but PIB error is unequal 0) // then just perform unit reset (6) (wait not needed). uint32_t l_command = 0; size_t op_size = sizeof(uint32_t); errlHndl_t l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &l_command, op_size, DEVICE_FSI_ADDRESS(ENGINE_RESET_REG)); if(l_err) { TRACFCOMP( g_trac_fsiscom, ERR_MRK"Error resetting FSI : %.4X", ERRL_GETRC_SAFE(l_err) ); l_err->plid(i_errlog->plid()); errlCommit(l_err,FSISCOM_COMP_ID); } nanosleep( 0,NS_PER_MSEC ); //sleep for ms }
void addScomFailFFDC( errlHndl_t i_err, TARGETING::Target* i_target, uint64_t i_addr ) { // Read some error regs from scom ERRORLOG::ErrlUserDetailsLogRegister l_scom_data(i_target); bool addit = false; TARGETING::TYPE l_type = TARGETING::TYPE_NA; if( i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL ) { l_type = TARGETING::TYPE_PROC; } else { l_type = i_target->getAttr<TARGETING::ATTR_TYPE>(); } //PBA scoms on the processor if( ((i_addr & 0xFFFFF000) == 0x00064000) && (TARGETING::TYPE_PROC == l_type) ) { addit = true; //look for hung operations on the PBA uint64_t ffdc_regs[] = { //grab the PBA buffers in case something is hung 0x02010850, //PBARBUFVAL0 0x02010851, //PBARBUFVAL1 0x02010852, //PBARBUFVAL2 0x02010858, //PBAWBUFVAL0 0x02010859, //PBAWBUFVAL1 0x020F0012, //PB_GP3 (has fence information) }; for( size_t x = 0; x < (sizeof(ffdc_regs)/sizeof(ffdc_regs[0])); x++ ) { l_scom_data.addData(DEVICE_SCOM_ADDRESS(ffdc_regs[x])); } } //EX scoms on the processor (not including PCB slave regs) else if( ((i_addr & 0xF0000000) == 0x10000000) && ((i_addr & 0x00FF0000) != 0x000F0000) && (TARGETING::TYPE_PROC == l_type) ) { addit = true; uint64_t ex_offset = 0xFF000000 & i_addr; //grab some data related to the PCB slave state uint64_t ffdc_regs[] = { 0x0F010B, //Special Wakeup 0x0F0012, //GP3 0x0F0100, //PowerManagement GP0 0x0F0106, //PFET Status Core 0x0F010E, //PFET Status ECO 0x0F0111, //PM State History }; for( size_t x = 0; x < (sizeof(ffdc_regs)/sizeof(ffdc_regs[0])); x++ ) { l_scom_data.addData(DEVICE_SCOM_ADDRESS(ex_offset|ffdc_regs[x])); } } //Any non-PCB Slave and non TP reg on the processor if( ((i_addr & 0x00FF0000) != 0x000F0000) && ((i_addr & 0xFF000000) != 0x00000000) && (TARGETING::TYPE_PROC == l_type) ) { addit = true; uint64_t chiplet_offset = 0xFF000000 & i_addr; //grab some data related to the PCB slave state uint64_t ffdc_regs[] = { 0x0F0012, //GP3 0x0F001F, //Error capture reg }; for( size_t x = 0; x < (sizeof(ffdc_regs)/sizeof(ffdc_regs[0])); x++ ) { l_scom_data.addData( DEVICE_SCOM_ADDRESS( chiplet_offset|ffdc_regs[x]) ); } //grab the clock/osc regs l_scom_data.addData(DEVICE_SCOM_ADDRESS(0x00050019)); l_scom_data.addData(DEVICE_SCOM_ADDRESS(0x0005001A)); //grab the clock regs via FSI too, just in case TARGETING::Target* mproc = NULL; TARGETING::targetService().masterProcChipTargetHandle(mproc); if( (i_target != TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) && (i_target != mproc) ) { l_scom_data.addData(DEVICE_FSI_ADDRESS(0x2864));//==2819 l_scom_data.addData(DEVICE_FSI_ADDRESS(0x2868));//==281A } } if( addit ) { l_scom_data.addToLog(i_err); } }
errlHndl_t fsiScomPerformOp(DeviceFW::OperationType i_opType, TARGETING::Target* i_target, void* io_buffer, size_t& io_buflen, int64_t i_accessType, va_list i_args) { errlHndl_t l_err = NULL; uint64_t l_scomAddr = va_arg(i_args,uint64_t); ioData6432 scratchData; uint32_t l_command = 0; uint32_t l_status = 0; bool need_unlock = false; size_t op_size = sizeof(uint32_t); mutex_t* l_mutex = NULL; do{ if( io_buflen != sizeof(uint64_t) ) { TRACFCOMP( g_trac_fsiscom, ERR_MRK "fsiScomPerformOp> Invalid data length : io_buflen=%d", io_buflen ); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_INVALID_LENGTH * @userdata1 SCOM Address * @userdata2 Data Length * @devdesc fsiScomPerformOp> Invalid data length (!= 8 bytes) * @custdesc A problem occurred during the IPL of the system: * Invalid data length for a SCOM operation. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_INVALID_LENGTH, l_scomAddr, TO_UINT64(io_buflen)); l_err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_LOW ); ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); break; } if( (l_scomAddr & 0xFFFFFFFF80000000) != 0) { TRACFCOMP( g_trac_fsiscom, ERR_MRK "fsiScomPerformOp> Address contains more than 31 bits : l_scomAddr=0x%.16X", l_scomAddr ); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_INVALID_ADDRESS * @userdata1 SCOM Address * @userdata2 Target HUID * @devdesc fsiScomPerformOp> Address contains * more than 31 bits. * @custdesc A problem occurred during the IPL of the system: * Invalid address on a SCOM operation. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_INVALID_ADDRESS, l_scomAddr, TARGETING::get_huid(i_target)); l_err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_LOW ); ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); break; } l_command = static_cast<uint32_t>(l_scomAddr & 0x000000007FFFFFFF); // use the chip-specific mutex attribute l_mutex = i_target->getHbMutexAttr<TARGETING::ATTR_FSI_SCOM_MUTEX>(); if(i_opType == DeviceFW::WRITE) { memcpy(&(scratchData.data64), io_buffer, 8); TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp> Write(l_scomAddr=0x%X, l_data0=0x%X, l_data1=0x%X)", l_scomAddr, scratchData.data32_0, scratchData.data32_1); // atomic section >> mutex_lock(l_mutex); need_unlock = true; //write bits 0-31 to data0 l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &scratchData.data32_0, op_size, DEVICE_FSI_ADDRESS(DATA0_REG)); if(l_err) { break; } //write bits 32-63 to data1 l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &scratchData.data32_1, op_size, DEVICE_FSI_ADDRESS(DATA1_REG)); if(l_err) { break; } //write to FSI2PIB command reg starts write operation //bit 0 high => write command l_command = 0x80000000 | l_command; l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &l_command, op_size, DEVICE_FSI_ADDRESS(COMMAND_REG)); if(l_err) { break; } //check status reg to see result l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &l_status, op_size, DEVICE_FSI_ADDRESS(STATUS_REG)); if(l_err) { break; } // Check the status reg for errors if( (l_status & PIB_ERROR_BITS) // PCB/PIB Errors || (l_status & PIB_ABORT_BIT) ) // PIB Abort { TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Write: PCB/PIB error received: l_status=0x%X)", l_status); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_WRITE_ERROR * @userdata1 SCOM Addr * @userdata2[00:31] Target HUID * @userdata2[32:63] SCOM Status Reg * @devdesc fsiScomPerformOp> Error returned * from SCOM Engine after write * @custdesc A problem occurred during the IPL of the system: * Error returned from SCOM engine after write. */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_WRITE_ERROR, l_scomAddr, TWO_UINT32_TO_UINT64( TARGETING::get_huid(i_target), l_status)); // call common error handler to do callouts and recovery pib_error_handler( i_target, l_err, l_status, l_scomAddr ); //Grab the PIB2OPB Status reg for a XSCOM Block error if( (l_status & 0x00007000) == 0x00001000 ) //piberr=001 { //@todo: Switch to external FSI FFDC interfaces RTC:35064 TARGETING::Target* l_master = NULL; TARGETING::targetService(). masterProcChipTargetHandle(l_master); uint64_t scomdata = 0; size_t scomsize = sizeof(uint64_t); errlHndl_t l_err2 = DeviceFW::deviceOp( DeviceFW::READ, l_master, &scomdata, scomsize, DEVICE_XSCOM_ADDRESS(0x00020001)); if( l_err2 ) { delete l_err2; } else { TRACFCOMP( g_trac_fsiscom, "PIB2OPB Status = %.16X", scomdata ); } } break; } // atomic section << need_unlock = false; mutex_unlock(l_mutex); } else if(i_opType == DeviceFW::READ) { TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp: Read(l_scomAddr=0x%.8X)", l_scomAddr); // atomic section >> mutex_lock(l_mutex); need_unlock = true; //write to FSI2PIB command reg starts read operation // bit 0 low -> read command l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &l_command, op_size, DEVICE_FSI_ADDRESS(COMMAND_REG)); if(l_err) { break; } //check ststus reg to see result l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &l_status, op_size, DEVICE_FSI_ADDRESS(STATUS_REG)); if(l_err) { break; } // Check the status reg for errors if( (l_status & PIB_ERROR_BITS) // PCB/PIB Errors || (l_status & PIB_ABORT_BIT) ) // PIB Abort { TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Read: PCB/PIB error received: l_status=0x%0.8X)", l_status); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_READ_ERROR * @userdata1 SCOM Addr * @userdata2[00:31] Target HUID * @userdata2[32:63] SCOM Status Reg * @devdesc fsiScomPerformOp> Error returned from SCOM Engine after read. * @custdesc A problem occurred during the IPL of the system: * Error returned from SCOM engine after read. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_READ_ERROR, l_scomAddr, TWO_UINT32_TO_UINT64( TARGETING::get_huid(i_target), l_status)); // call common error handler to do callouts and recovery pib_error_handler( i_target, l_err, l_status, l_scomAddr ); break; } //read bits 0-31 to data0 l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &scratchData.data32_0, op_size, DEVICE_FSI_ADDRESS(DATA0_REG)); if(l_err) { break; } //read bits 32-63 to data1 l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &scratchData.data32_1, op_size, DEVICE_FSI_ADDRESS(DATA1_REG)); if(l_err) { break; } // atomic section << need_unlock = false; mutex_unlock(l_mutex); TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp: Read: l_scomAddr=0x%X, l_data0=0x%X, l_data1=0x%X", l_scomAddr, scratchData.data32_0, scratchData.data32_1); memcpy(io_buffer, &(scratchData.data64), 8); } else { TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Unsupported Operation Type: i_opType=%d)", i_opType); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_INVALID_OPTYPE * @userdata1[0:31] Operation Type (i_opType) : 0=READ, 1=WRITE * @userdata1[32:64] Input scom address * @userdata2 Target HUID * @devdesc fsiScomPerformOp> Unsupported Operation Type specified * @custdesc A problem occurred during the IPL of the system: * Unsupported SCOM operation type. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_INVALID_OPTYPE, TWO_UINT32_TO_UINT64(i_opType, l_scomAddr), TARGETING::get_huid(i_target), true /*SW error*/); //Add this target to the FFDC ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); break; } }while(0); if( need_unlock && l_mutex ) { mutex_unlock(l_mutex); } return l_err; }