//------------------------------------------------------------------------------
// 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;
    }
示例#2
0
//------------------------------------------------------------------------------
// function: init_tod_node
//
// parameters: i_tod_node  Reference to TOD topology (FAPI targets included within)
//
// returns: FAPI_RC_SUCCESS if TOD topology is successfully initialized
//          else FAPI or ECMD error is sent through
//------------------------------------------------------------------------------
fapi::ReturnCode init_tod_node(const tod_topology_node* i_tod_node)
{
    fapi::ReturnCode rc;
    ecmdDataBufferBase data(64);
    uint32_t rc_ecmd = 0;
    uint32_t tod_init_pending_count = 0; // Timeout counter for bits that are cleared by hardware
    fapi::Target* target = i_tod_node->i_target;

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

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

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

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

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

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

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

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

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

    } while(0);

    FAPI_INF("init_tod_node: End");
    return rc;
}
//------------------------------------------------------------------------------
// 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;
}