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