Exemple #1
0
// Function Specification
//
// Name:  proc_gpsm_dcm_sync_enable_pstates_smh
//
// Description:  Step through all the states & synch needed to enable
//               Pstates on both master & slave on a DCM.  This also
//               works for a SCM, which will act as DCM master (as far
//               as this function is concerned.)
//
// End Function Specification
void proc_gpsm_dcm_sync_enable_pstates_smh(void)
{
    // Static Locals
    static GpsmEnablePstatesMasterInfo l_master_info;
    static Pstate l_voltage_pstate, l_freq_pstate;

    // Local Variables
    int l_rc = 0;
    errlHndl_t l_errlHndl = NULL;

    if(!gpsm_dcm_slave_p())
    {
        // ---------------------------------------
        // SCM or DCM Master
        // ---------------------------------------
        switch( G_proc_dcm_sync_state.sync_state_master )
        {
            case PROC_GPSM_SYNC_NO_PSTATE_TABLE:
                // Waiting for Pstate Table from TMGT
                break;

            case PROC_GPSM_SYNC_PSTATE_TABLE_INSTALLED:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);
                // DCM SYNC (MasterWaitForSlave):  Wait for slave to install Pstate table
                if(gpsm_dcm_mode_p()){
                    if( G_proc_dcm_sync_state.sync_state_slave == PROC_GPSM_SYNC_PSTATE_TABLE_INSTALLED)
                    {
                        // Move to next state in state machine
                        G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_READY_TO_ENABLE_MASTER;
                    }
                }
                else
                {
                    // Move to next state in state machine
                    G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_READY_TO_ENABLE_MASTER;
                }
                break;

            case  PROC_GPSM_SYNC_READY_TO_ENABLE_MASTER:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);

                // Pstate tables has been installed, so now Master can start to enable Pstates
                l_rc = gpsm_enable_pstates_master(&l_master_info, &l_voltage_pstate, &l_freq_pstate);
                if(l_rc)
                {
                    // Error
                    TRAC_ERR("MSTR: gpsm_enable_pstates_master failed with rc=0x%08x", l_rc);
                    G_proc_dcm_sync_state.sync_state_master =  PROC_GPSM_SYNC_PSTATE_ERROR;
                    break;
                }
                TRAC_IMP("MSTR: Initial Pstates: V: %d, F: %d\n",l_voltage_pstate, l_freq_pstate);

                // DCM SYNC (Master2Slave):  Send V & F Pstate to slave
                G_proc_dcm_sync_state.dcm_pair_id = G_pob_id.chip_id;
                G_proc_dcm_sync_state.pstate_v = l_voltage_pstate;
                G_proc_dcm_sync_state.pstate_f = l_freq_pstate;

                // Move to next state in state machine
                G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_PSTATE_MASTER_ENABLED;
                break;

            case  PROC_GPSM_SYNC_PSTATE_MASTER_ENABLED:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);
                // DCM SYNC (MasterWaitForSlave):  Wait for slave to complete gpsm_enable_pstates_slave()
                if(gpsm_dcm_mode_p()){
                    if( G_proc_dcm_sync_state.sync_state_slave == PROC_GPSM_SYNC_PSTATE_SLAVE_ENABLED)
                    {
                        // Move to next state in state machine
                        G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_READY_TO_ENABLE_SLAVE;
                    }
                }
                else
                {
                    G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_READY_TO_ENABLE_SLAVE;
                }
                break;


            case PROC_GPSM_SYNC_READY_TO_ENABLE_SLAVE:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);

                // Master does next step of enabling Pstates, now that slave has done it's enable
                l_rc = gpsm_enable_pstates_slave(&l_master_info, l_voltage_pstate, l_freq_pstate);
                if(l_rc)
                {
                    // Error
                    TRAC_ERR("MSTR: gpsm_enable_pstates_slave failed with rc=0x%08x", l_rc);
                    G_proc_dcm_sync_state.sync_state_master =  PROC_GPSM_SYNC_PSTATE_ERROR;
                    break;
                }
                TRAC_INFO("MSTR: Completed DCM Pstate Slave Init\n");
                G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_PSTATE_SLAVE_ENABLED;
                break;

            case PROC_GPSM_SYNC_PSTATE_SLAVE_ENABLED:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);
                // Master puts this chip in Pstate HW mode
                l_rc = gpsm_hw_mode();
                if(l_rc)
                {
                    // Error
                    TRAC_ERR("MSTR: gpsm_hw_mode failed with rc=0x%08x", l_rc);
                    G_proc_dcm_sync_state.sync_state_master =  PROC_GPSM_SYNC_PSTATE_ERROR;
                    break;
                }
                // DCM SYNC (Master2Slave):  Tell Slave Master has entered HW mmode
                G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_PSTATE_HW_MODE;
                break;

            case PROC_GPSM_SYNC_PSTATE_HW_MODE:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);
                // DCM SYNC (Master2Slave): Wait for Slave to Enter HW Mode
                if(gpsm_dcm_mode_p()){
                    if( G_proc_dcm_sync_state.sync_state_slave == PROC_GPSM_SYNC_PSTATE_HW_MODE)
                    {
                        TRAC_INFO("MSTR: Completed DCM Pstate Enable");
                        G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED;

                        //do additional setup if in kvm mode
                        proc_pstate_kvm_setup();
                    }
                }
                else
                {
                    G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED;
                    TRAC_INFO("MSTR: Completed SCM Pstate Enable");

                    //do additional setup if in kvm mode
                    proc_pstate_kvm_setup();
                }
                break;

            case PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED:
                // Final State
                // Pstates Enabled on both modules in DCM
                break;

           case PROC_GPSM_SYNC_PSTATE_ERROR:
               // Do nothing, something will have to come and kick us out of this state
               break;

            default:
                G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_NO_PSTATE_TABLE;
                break;
        }
    }
    else if (gpsm_dcm_slave_p())
    {
        // ---------------------------------------
        // DCM Slave
        //  - Don't need to check if DCM, since we can't come in here unless DCM
        // ---------------------------------------

       switch( G_proc_dcm_sync_state.sync_state_slave)
       {
           case PROC_GPSM_SYNC_NO_PSTATE_TABLE:
               // Waiting for Pstate Table from TMGT
               break;

           case PROC_GPSM_SYNC_PSTATE_TABLE_INSTALLED:
               // Pstate table has been installed, but slave needs to wait
               // for master before it can do anything else.

               // DCM SYNC (SlaveWaitForMaster):  Send V & F Pstate to slave
               // Wait for Master to complete gpsm_enable_pstates_master()
               // before running gpsm_enable_pstates_slave()
               if( G_proc_dcm_sync_state.sync_state_master == PROC_GPSM_SYNC_PSTATE_MASTER_ENABLED)
               {
                   // Go to next state
                   G_proc_dcm_sync_state.sync_state_slave = PROC_GPSM_SYNC_PSTATE_MASTER_ENABLED;
               }
               break;


           case PROC_GPSM_SYNC_PSTATE_MASTER_ENABLED:
               PROC_DBG("GPST DCM Slave State %d\n",G_proc_dcm_sync_state.sync_state_slave);
               // Read the initial Pstates from the data DCM master sent
               l_voltage_pstate = G_proc_dcm_sync_state.pstate_v;
               l_freq_pstate = G_proc_dcm_sync_state.pstate_f;

               // NULL is passed to this function when run on dcm slave
               l_rc = gpsm_enable_pstates_slave(NULL, l_voltage_pstate, l_freq_pstate);
               if(l_rc)
               {
                   // Error
                   TRAC_ERR("SLV: gpsm_enable_pstates_slave failed with rc=0x%08x", l_rc);
                   G_proc_dcm_sync_state.sync_state_slave =  PROC_GPSM_SYNC_PSTATE_ERROR;
                   break;
               }
               TRAC_INFO("SLV: Completed DCM Pstate Slave Init\n");

               // DCM SYNC (Slave2Master):
               // Tell Master that slave has run gpsm_enable_pstates_slave()

               // Go to next state
               G_proc_dcm_sync_state.sync_state_slave = PROC_GPSM_SYNC_PSTATE_SLAVE_ENABLED;
               break;

           case PROC_GPSM_SYNC_PSTATE_SLAVE_ENABLED:
               // DCM SYNC (SlaveWaitForMaster):  Wait for Master to run gpsm_hw_mode
               if( G_proc_dcm_sync_state.sync_state_master == PROC_GPSM_SYNC_PSTATE_HW_MODE)
               {
                   // Enter Pstate HW mode
                   l_rc = gpsm_hw_mode();
                   if(l_rc)
                   {
                       // Error
                       TRAC_ERR("SLV: gpsm_hw_mode failed with rc=0x%08x", l_rc);
                       G_proc_dcm_sync_state.sync_state_slave =  PROC_GPSM_SYNC_PSTATE_ERROR;
                       break;
                   }

                   // DCM SYNC (Slave2Master): Tell master that DCM slave made it to HW mode

                   // Go to next state
                   G_proc_dcm_sync_state.sync_state_slave = PROC_GPSM_SYNC_PSTATE_HW_MODE;
               }
               break;

           case PROC_GPSM_SYNC_PSTATE_HW_MODE:
               // Slave & Master now both know each other has HW mode enabled
               if( G_proc_dcm_sync_state.sync_state_master == PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED)
               {
                   G_proc_dcm_sync_state.sync_state_slave = PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED;
                   TRAC_INFO("SLV: Completed DCM Pstate Enable");

                   //do additional setup if in kvm mode
                   proc_pstate_kvm_setup();
               }
               break;

           case PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED:
               // Final State
               // Pstates Enabled on both modules in DCM
               break;

           case PROC_GPSM_SYNC_PSTATE_ERROR:
               // Do nothing, something will have to come and kick us out of this state
               break;

           default:
               G_proc_dcm_sync_state.sync_state_slave = PROC_GPSM_SYNC_NO_PSTATE_TABLE;
               break;

       }
    }

    // If we are in the process of running through the state machine,
    // we will do a sem_post to speed up the DCOM Thread and step us
    // through faster.
    if( PROC_GPSM_SYNC_NO_PSTATE_TABLE != proc_gpsm_dcm_sync_get_my_state()
        && !proc_is_hwpstate_enabled() )
    {
       ssx_semaphore_post(&G_dcomThreadWakeupSem);
    }

    // If we broke out of loops above because of an error, create an
    // error log and return it to caller.
    if(l_rc)
    {
        /* @
         * @errortype
         * @moduleid    PROC_ENABLE_PSTATES_SMH_MOD
         * @reasoncode  SSX_GENERIC_FAILURE
         * @userdata1   SRAM Address of the Pstate Table
         * @userdata2   Return Code of call that failed
         * @userdata4   OCC_NO_EXTENDED_RC
         * @devdesc     Failed to install Pstate Table
         */
        l_errlHndl = createErrl(
                PROC_ENABLE_PSTATES_SMH_MOD,        //modId
                SSX_GENERIC_FAILURE,                //reasoncode
                OCC_NO_EXTENDED_RC,                 //Extended reason code
                ERRL_SEV_PREDICTIVE,                //Severity
                NULL,    //TODO: create trace       //Trace Buf
                DEFAULT_TRACE_SIZE,                 //Trace Size
                (uint32_t) &G_global_pstate_table,  //userdata1
                l_rc);                              //userdata2
        addCalloutToErrl(l_errlHndl,
                         ERRL_CALLOUT_TYPE_COMPONENT_ID,
                         ERRL_COMPONENT_ID_FIRMWARE,
                         ERRL_CALLOUT_PRIORITY_HIGH);
        addCalloutToErrl(l_errlHndl,
                         ERRL_CALLOUT_TYPE_HUID,
                         G_sysConfigData.proc_huid,
                         ERRL_CALLOUT_PRIORITY_LOW);
        REQUEST_RESET(l_errlHndl);
    }

    return;
}
Exemple #2
0
// Function Specification
//
// Name: task_dcom_tx_slv_outbox
//
// Description: Copy slave outboxes from SRAM to main memory
//              so slave can send data to master
//
// Task Flags:  RTL_FLAG_NONMSTR, RTL_FLAG_MSTR, RTL_FLAG_OBS, RTL_FLAG_ACTIVE,
//              RTL_FLAG_NOAPSS, RTL_FLAG_RUN, RTL_FLAG_MSTR_READY
//
// End Function Specification
void task_dcom_tx_slv_outbox( task_t *i_self)
{
    static bool l_error = FALSE;
    uint32_t    l_orc = OCC_SUCCESS_REASON_CODE;
    uint32_t    l_orc_ext = OCC_NO_EXTENDED_RC;
    // Use a static local bool to track whether the BCE request used
    // here has ever been successfully created at least once
    static bool L_bce_slv_outbox_tx_request_created_once = FALSE;

    DCOM_DBG("3. TX Slave Outboxes\n");

    do
    {
        // Build/setup outbox
        uint32_t l_addr_in_mem = dcom_build_slv_outbox();
        uint32_t l_ssxrc = 0;

        // See dcomMasterRx.c/task_dcom_rx_slv_outboxes for details on the
        // checking done here before creating and scheduling the request.
        bool l_proceed_with_request_and_schedule = FALSE;
        int l_req_idle = async_request_is_idle(&(G_slv_outbox_tx_pba_request.request));
        int l_req_complete = async_request_completed(&(G_slv_outbox_tx_pba_request.request));

        if (!L_bce_slv_outbox_tx_request_created_once)
        {
            // Do this case first, all other cases assume that this is
            // true!
            // This is the first time we have created a request so
            // always proceed with request create and schedule
            l_proceed_with_request_and_schedule = TRUE;
        }
        else if (l_req_idle && l_req_complete)
        {
            // Most likely case first.  The request was created
            // and scheduled and has completed without error.  Proceed.
            // Proceed with request create and schedule.
            l_proceed_with_request_and_schedule = TRUE;
        }
        else if (l_req_idle && !l_req_complete)
        {
            // There was an error on the schedule request or the request
            // was scheduled but was canceled, killed or errored out.
            // Proceed with request create and schedule.
            l_proceed_with_request_and_schedule = TRUE;

            // Trace important information from the request
            TRAC_INFO("BCE slv outbox tx request idle but not complete, \
                      callback_rc=%d options=0x%x state=0x%x abort_state=0x%x \
                      completion_state=0x%x",
                      G_slv_outbox_tx_pba_request.request.callback_rc,
                      G_slv_outbox_tx_pba_request.request.options,
                      G_slv_outbox_tx_pba_request.request.state,
                      G_slv_outbox_tx_pba_request.request.abort_state,
                      G_slv_outbox_tx_pba_request.request.completion_state);
            TRAC_INFO("Proceeding with BCE slv outbox tx request and schedule");
        }
        else if (!l_req_idle && !l_req_complete)
        {
            // The request was created and scheduled but is still in
            // progress or still enqueued OR there was some error
            // creating the request so it was never scheduled.  The latter
            // case is unlikely and will generate an error message when
            // it occurs.  It will also have to happen after the request
            // was created at least once or we'll never get here.  If the
            // request does fail though before the state parms in the
            // request are reset (like a bad parameter error), then this
            // represents a hang condition that we can't recover from.
            // DO NOT proceed with request create and schedule.
            l_proceed_with_request_and_schedule = FALSE;

            // Trace important information from the request
            TRAC_INFO("BCE slv outbox tx request not idle and not complete, \
                      callback_rc=%d options=0x%x state=0x%x abort_state=0x%x \
                      completion_state=0x%x",
                      G_slv_outbox_tx_pba_request.request.callback_rc,
                      G_slv_outbox_tx_pba_request.request.options,
                      G_slv_outbox_tx_pba_request.request.state,
                      G_slv_outbox_tx_pba_request.request.abort_state,
                      G_slv_outbox_tx_pba_request.request.completion_state);
            TRAC_INFO("NOT proceeding with BCE slv outbox tx request and schedule");
        }
Exemple #3
0
// Function Specification
//
// Name: task_dcom_parse_occfwmsg
//
// Description: Purpose of this task is to handle and acknowledge
//              fw messages passed from Master to Slave and vice versa.
//
// End Function Specification
void task_dcom_parse_occfwmsg(task_t *i_self)
{
    if(G_occ_role == OCC_MASTER)
    {
        // Local slave index counter
        uint32_t l_slv_idx      = 0;

        // Loop and collect occ data for each slave occ
        for(; l_slv_idx < MAX_OCCS; l_slv_idx++)
        {
            // Verify all slave are in correct state and mode
            G_dcom_slv_outbox_rx[l_slv_idx].occ_fw_mailbox[0] = CURRENT_STATE();

            if(G_sysConfigData.system_type.kvm )
            {
                G_dcom_slv_outbox_rx[l_slv_idx].occ_fw_mailbox[1] = G_occ_external_req_mode_kvm;
            }
            else
            {
                G_dcom_slv_outbox_rx[l_slv_idx].occ_fw_mailbox[1] = CURRENT_MODE();
            }

            // Acknowledge all slave event flags
            G_slave_event_flags_ack[l_slv_idx] = G_dcom_slv_outbox_rx[l_slv_idx].occ_fw_mailbox[3];

            // Clear master event flags if slave has acknowledged them and the event has cleared
            G_master_event_flags &= ~G_dcom_slv_outbox_rx[l_slv_idx].occ_fw_mailbox[2];

        }

    }//End master role check

    // Check if master has changed state and mode and update if changed
    // so that we can handle it in a thread.
    if( (G_occ_master_state != G_dcom_slv_inbox_rx.occ_fw_mailbox[0])
        || (G_occ_master_mode != G_dcom_slv_inbox_rx.occ_fw_mailbox[1]) )
    {
        if( ! isSafeStateRequested() )
        {
            G_occ_master_state = G_dcom_slv_inbox_rx.occ_fw_mailbox[0];
            G_occ_master_mode  = G_dcom_slv_inbox_rx.occ_fw_mailbox[1];
            ssx_semaphore_post(&G_dcomThreadWakeupSem);
        }
    }

    // If we are master, we don't want to update based on
    // the data sent to us, because it corrupts the 'golden' data
    // If we are in standby, we don't want to update because
    // the data may not have been set up yet, and would be set to zero.
    if(OCC_MASTER != G_occ_role )
    {
        // Update the system mode frequencies if they have changed
        int l_mode    = 0;
        bool l_change = FALSE;
        bool l_all_zero = TRUE;

        // Check if all values are zero
        for(l_mode = 0; l_mode<OCC_MODE_COUNT; l_mode++)
        {
            if( (0 != G_dcom_slv_inbox_rx.sys_mode_freq.table[l_mode]) )
            {
                l_all_zero = FALSE;
                break;
            }
        }

        extern data_cnfg_t * G_data_cnfg;
        if( l_all_zero == FALSE)
        {
            for(l_mode =0; l_mode<OCC_MODE_COUNT; l_mode++)
            {
                // Don't trust a frequency of 0x0000
                if( (0 != G_dcom_slv_inbox_rx.sys_mode_freq.table[l_mode]) )
                {
                    if(G_sysConfigData.sys_mode_freq.table[l_mode]
                            != G_dcom_slv_inbox_rx.sys_mode_freq.table[l_mode])
                    {
                        TRAC_INFO("New Frequency for Mode %d: Old: %d MHz -> New: %d MHz",l_mode,
                                G_sysConfigData.sys_mode_freq.table[l_mode],
                                G_dcom_slv_inbox_rx.sys_mode_freq.table[l_mode]);

                        // Update mode frequency
                        G_sysConfigData.sys_mode_freq.table[l_mode] =
                            G_dcom_slv_inbox_rx.sys_mode_freq.table[l_mode];

                        l_change = TRUE;
                    }
                }
            }

            if(l_change)
            {
                // Update "update count" for debug purposes
                G_sysConfigData.sys_mode_freq.update_count =
                    G_dcom_slv_inbox_rx.sys_mode_freq.update_count;

                // Change Data Request Mask to indicate we got this data
                extern data_cnfg_t * G_data_cnfg;
                G_data_cnfg->data_mask |= DATA_MASK_FREQ_PRESENT;

                // Notify AMEC that the frequencies have changed
                AMEC_data_change(DATA_MASK_FREQ_PRESENT);
            }
        }
        else
        {
            // Clear Data Request Mask and data
            G_data_cnfg->data_mask &= (~DATA_MASK_FREQ_PRESENT);
            memset(&G_sysConfigData.sys_mode_freq.table[0], 0, sizeof(G_sysConfigData.sys_mode_freq.table));
        }
    }

    // Copy mnfg parameters into g_amec structure
    g_amec->foverride_enable = G_dcom_slv_inbox_rx.foverride_enable;
    g_amec->foverride = G_dcom_slv_inbox_rx.foverride;

    // Copy IPS parameters sent by Master OCC
    g_amec->slv_ips_freq_request = G_dcom_slv_inbox_rx.ips_freq_request;

    // Copy DPS tunable parameters sent by Master OCC if required
    if(G_dcom_slv_inbox_rx.tunable_param_overwrite)
    {
        AMEC_part_overwrite_dps_parameters();

        if(G_dcom_slv_inbox_rx.tunable_param_overwrite == 1)
        {
            g_amec->slv_dps_param_overwrite = TRUE;
        }
        else
        {
            g_amec->slv_dps_param_overwrite = FALSE;
        }
    }

    // Copy soft frequency boundaries sent by Master OCC
    g_amec->part_config.part_list[0].soft_fmin = G_dcom_slv_inbox_rx.soft_fmin;
    g_amec->part_config.part_list[0].soft_fmax = G_dcom_slv_inbox_rx.soft_fmax;

    // acknowledge all masters event flags
    G_master_event_flags_ack = G_dcom_slv_inbox_rx.occ_fw_mailbox[2];

    // clear slave event flags if master has acknowledged them and the event has cleared
    G_slave_event_flags = (G_slave_event_flags & (~(G_dcom_slv_inbox_rx.occ_fw_mailbox[3])));
}
Exemple #4
0
//*************************************************************************
// Functions
//*************************************************************************
// Function errlTestMain
//
// Name: sensorTestMain
//
// Description: Entry point function
//
// End Function Specification
errlHndl_t errlTestMain(void * i_arg)
{

    errlHndl_t l_err = NULL;
    uint16_t l_modId = 0;
    uint32_t l_rc = ERRL_RC_SUCCESS;

    ERRL_DBG("Enter errlTestMain\n");

    do
    {
        l_rc = errlTestErrorHandling();
        l_modId = TEST_ERROR_HANDLING;

        if( l_rc != ERRL_RC_SUCCESS)
        {
            TRAC_INFO("Failure on error handling test");
            break;
        };

        l_rc = errlTestCreateCommitDeleteLog();
        l_modId = TEST_CREATE_COMMIT_DELETE_LOG ;
        if( l_rc != ERRL_RC_SUCCESS)
        {
            TRAC_INFO("Failure on Log test");
            break;
        }

        l_rc = errlTestAddUsrDtlsToErrl();
        l_modId = TEST_ADD_USRDTLS_TO_ERRL ;
        if( l_rc != ERRL_RC_SUCCESS)
        {
            TRAC_INFO("Failure on add user detail test");
            break;
        }

        l_rc = errlTestAddTraceToErrl();
        l_modId = TEST_ADD_TRACE_TO_ERRL ;
        if( l_rc != ERRL_RC_SUCCESS)
        {
            TRAC_INFO("Failure on add trace test");
            break;
        }

        l_rc = errlTestTime();
        l_modId = TEST_TIME ;
        if( l_rc != ERRL_RC_SUCCESS)
        {
            TRAC_INFO("Failure on time test");
            break;
        }

        l_rc = errlTestCreate2InfoCallhomeLog();
        l_modId = TEST_CREATE2INFO_CALLHOMELOG ;
        if( l_rc != ERRL_RC_SUCCESS)
        {
            TRAC_INFO("Failure on create call home log test");
            break;
        }

        l_rc = errlTestCreateMaxLogs();
        l_modId = TEST_CREATE_MAX_LOGS ;
        if( l_rc != ERRL_RC_SUCCESS)
        {
            TRAC_INFO("Failure on create max logs test");
            break;
        }

        l_rc = errlTestCallouts();
        l_modId = TEST_CALLOUTS ;
        if( l_rc != ERRL_RC_SUCCESS)
        {
            TRAC_INFO("Failure on callouts test");
            break;
        }

        l_rc = errlTestSetErrlSevToInfo();
        l_modId = TEST_SET_ERRLSEV_TO_INFO ;
        if( l_rc != ERRL_RC_SUCCESS)
        {
            TRAC_INFO("Failure on SetErrlSevToInfo test");
            break;
        }

    } while (0);

    if( l_rc != ERRL_RC_SUCCESS)
    {
        ERRL_DBG("**********************************************");
        ERRL_DBG("* errl Test Failed (errlTest.c): line: %d",l_rc);
        ERRL_DBG("**********************************************");
        /* @
         * @errortype
         * @moduleid       TEST_APLT_MODID_ERRLTEST
         * @reasoncode     INTERNAL_FAILURE
         * @userdata1      Test Applet ID
         * @userdata2      Return Code
         * @userdata4      OCC_NO_EXTENDED_RC
         * @devdesc        Failure executing test applet
         */
        l_err = createErrl(TEST_APLT_MODID_ERRLTEST,
                           INTERNAL_FAILURE,
                           OCC_NO_EXTENDED_RC,
                           ERRL_SEV_INFORMATIONAL,
                           NULL,
                           0,
                           ERRL_TEST_APLT,
                           l_rc);
    }
    else
    {
        ERRL_DBG("**********************************************");
        ERRL_DBG("* errl Test Passed (errlTest.c)");
        ERRL_DBG("**********************************************");
    }

    ERRL_DBG("Exit errlTestMain\n");

    return l_err;
}
Exemple #5
0
// Function Specification
//
// Name: amec_slv_mem_voting_box
//
// Description: Slave OCC's voting box that decides the memory speed request.
//              This function will run every tick.
//
// Thread: RealTime Loop
//
// Task Flags:
//
// End Function Specification
void amec_slv_mem_voting_box(void)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    UINT16                   l_vote;
    amec_mem_voting_reason_t l_reason;
    opal_mem_voting_reason_t  kvm_reason;
    static INT16             l_slew_step = AMEC_MEMORY_STEP_SIZE;
    static bool              L_throttle_traced = FALSE;

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/
    // Start with max allowed speed
    l_vote     = AMEC_MEMORY_MAX_STEP;
    l_reason   = AMEC_MEM_VOTING_REASON_INIT;
    kvm_reason = NO_THROTTLE;

    // Memory throttled due to power cap.  if also throttled due to
    // over temp, report over-temp as the reason to OPAL.
    if (g_amec->pcap.active_mem_level != 0)
    {
        kvm_reason = POWER_CAP;
    }

    // Check vote from Centaur thermal control loop
    if (l_vote > g_amec->thermalcent.speed_request)
    {
        l_vote = g_amec->thermalcent.speed_request;
        l_reason = AMEC_MEM_VOTING_REASON_CENT;
        kvm_reason = MEMORY_OVER_TEMP;
    }

    // Check vote from DIMM thermal control loop
    if (l_vote > g_amec->thermaldimm.speed_request)
    {
        l_vote = g_amec->thermaldimm.speed_request;
        l_reason = AMEC_MEM_VOTING_REASON_DIMM;
        kvm_reason = MEMORY_OVER_TEMP;
    }

    // Check if memory autoslewing is enabled
    if (g_amec->mnfg_parms.mem_autoslew)
    {
        //check if we've reached the max setting and need to start going down
        if(g_amec->mem_speed_request >= AMEC_MEMORY_MAX_STEP)
        {
            g_amec->mnfg_parms.mem_slew_counter++;
            l_slew_step = -AMEC_MEMORY_STEP_SIZE;
        }

        //check if we've reached the min setting and need to start going up
        else if(g_amec->mem_speed_request <= AMEC_MEMORY_MIN_STEP)
        {
            g_amec->mnfg_parms.mem_slew_counter++;
            l_slew_step = AMEC_MEMORY_STEP_SIZE;
        }

        l_vote = g_amec->mem_speed_request + l_slew_step;
        l_reason = AMEC_MEM_VOTING_REASON_SLEW;
    }

    // Store final vote and vote reason in g_amec
    g_amec->mem_throttle_reason = l_reason;
    g_amec->mem_speed_request = l_vote;

    //trace changes in memory throttling
    if(l_reason != AMEC_MEM_VOTING_REASON_INIT)
    {
        if(!L_throttle_traced)
        {
            L_throttle_traced = TRUE;
            TRAC_INFO("Memory is being throttled. reason[%d] vote[%d] "
                      "cent_expired[0x%02x] dimm_expired[0x%08x%08x]",
                       l_reason,
                       l_vote,
                       G_cent_temp_expired_bitmap,
                       G_dimm_temp_expired_bitmap.words[0],
                       G_dimm_temp_expired_bitmap.words[1]);
        }
    }
    else
    {
        if(L_throttle_traced)
        {
            L_throttle_traced = FALSE;
            TRAC_INFO("Memory is no longer being throttled");
        }
    }

    //check if we need to update the throttle reason in OPAL table
    if(G_sysConfigData.system_type.kvm &&
       (kvm_reason != G_amec_opal_mem_throt_reason))
    {
        //Notify dcom thread to update the table
        G_amec_opal_mem_throt_reason = kvm_reason;
        ssx_semaphore_post(&G_dcomThreadWakeupSem);
    }

    return;
}
Exemple #6
0
// Function Specification
//
// Name: amec_slv_check_perf
//
// Description: Slave OCC's Detect and log degraded performance errors
//              This function will run every tick.
//
// Thread: RealTime Loop
//
// Task Flags:
//
// End Function Specification
void amec_slv_check_perf(void)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    static BOOLEAN          l_prev_ovs_state = FALSE;
    static BOOLEAN          l_prev_pcap_state = FALSE;
    static ERRL_SEVERITY    l_pcap_sev =  ERRL_SEV_PREDICTIVE;
    static BOOLEAN          l_throttle_traced = FALSE;
    static uint64_t         l_time = 0;

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/

    do
    {
        // was frequency limited by power ?
        if ( G_non_dps_power_limited != TRUE )
        {
            if(l_throttle_traced)
            {
                TRAC_INFO("Frequency not limited by power algorithms anymore");
                l_throttle_traced = FALSE;
            }
            // we are done break and return
            break;
        }

        // frequency limited due to oversubscription condition ?
        if ( AMEC_INTF_GET_OVERSUBSCRIPTION() == TRUE )
        {
            if ( l_prev_ovs_state == TRUE)
            {
                // we are done break and return
                break;
            }
            else
            {
                // log this error ONLY ONCE per IPL
                l_prev_ovs_state = TRUE;

                TRAC_ERR("Frequency limited due to oversubscription condition(mode:%d, state:%d)",
                          CURRENT_MODE(), CURRENT_STATE());
                l_throttle_traced = TRUE;
                l_time = ssx_timebase_get();

                // log error that calls out OVS procedure
                // set error severity to RRL_SEV_PREDICTIVE

                // Updated the RC to match the actual RC passed to createErrl()
                /* @
                 * @errortype
                 * @moduleid    AMEC_SLAVE_CHECK_PERFORMANCE
                 * @reasoncode  OVERSUB_LIMIT_ALERT
                 * @userdata1   Previous OVS State
                 * @userdata4   ERC_AMEC_SLAVE_OVS_STATE
                 * @devdesc     Frequency limited due to oversubscription condition
                 */
                errlHndl_t l_errl = createErrl(AMEC_SLAVE_CHECK_PERFORMANCE, //modId
                                              OVERSUB_LIMIT_ALERT,           //reasoncode
                                              ERC_AMEC_SLAVE_OVS_STATE,      //Extended reason code
                                              ERRL_SEV_PREDICTIVE,           //Severity
                                              NULL,                          //Trace Buf
                                              DEFAULT_TRACE_SIZE,            //Trace Size
                                              l_prev_ovs_state,              //userdata1
                                              0);                            //userdata2

                // Callout to Oversubscription
                addCalloutToErrl(   l_errl,
                                    ERRL_CALLOUT_TYPE_COMPONENT_ID,
                                    ERRL_COMPONENT_ID_OVERSUBSCRIPTION,
                                    ERRL_CALLOUT_PRIORITY_HIGH
                                );

                // Callout to APSS
                addCalloutToErrl(   l_errl,
                                    ERRL_CALLOUT_TYPE_HUID,
                                    G_sysConfigData.apss_huid,
                                    ERRL_CALLOUT_PRIORITY_MED
                                );

                // Callout to Firmware
                addCalloutToErrl(   l_errl,
                                    ERRL_CALLOUT_TYPE_COMPONENT_ID,
                                    ERRL_COMPONENT_ID_FIRMWARE,
                                    ERRL_CALLOUT_PRIORITY_LOW
                                );

                // and sets the consolidate action flag
                setErrlActions( l_errl, ERRL_ACTIONS_CONSOLIDATE_ERRORS );

                // Commit Error
                commitErrl(&l_errl);

                // we are done lets break
                break;
            }
        }

        uint16_t l_snrBulkPwr = AMECSENSOR_PTR(PWRSYS)->sample;

        // frequency limited due to system power cap condition ?
        if (( l_snrBulkPwr > (G_sysConfigData.pcap.system_pcap - PDROP_THRESH) )
            &&
            ( G_sysConfigData.pcap.current_pcap == 0 ))
        {
            if ( l_prev_pcap_state == TRUE)
            {
                // we are done break and return
                break;
            }
            else
            {
                //log this error ONLY ONCE per IPL
                l_prev_pcap_state = TRUE;

                TRAC_ERR("Frequency limited due to power cap condition(mode:%d, state:%d)",
                         CURRENT_MODE(), CURRENT_STATE());

                TRAC_ERR("SnrBulkPwr %d > Sys Pcap %d ",l_snrBulkPwr,
                         G_sysConfigData.pcap.system_pcap );

                TRAC_ERR("SnrFanPwr %d, SnrIOPwr %d, SnrStoragePwr %d, SnrGpuPrw %d ",
                        AMECSENSOR_PTR(PWRFAN)->sample,
                        AMECSENSOR_PTR(PWRIO)->sample,
                        AMECSENSOR_PTR(PWRSTORE)->sample,
                        AMECSENSOR_PTR(PWRGPU)->sample );

                TRAC_ERR("SnrProcPwr 0 %d, SnrProcPwr 1 %d, SnrProcPwr 2 %d, SnrProcPwr 3 %d",
                        g_amec->proc_snr_pwr[0],
                        g_amec->proc_snr_pwr[1],
                        g_amec->proc_snr_pwr[2],
                        g_amec->proc_snr_pwr[3] );

                TRAC_ERR("SnrMemPwr 0 %d, SnrMemPwr 1 %d, SnrMemPwr 2 %d, SnrMemPwr 3 %d",
                        g_amec->mem_snr_pwr[0],
                        g_amec->mem_snr_pwr[1],
                        g_amec->mem_snr_pwr[2],
                        g_amec->mem_snr_pwr[3] );


                l_throttle_traced = TRUE;
                l_time = ssx_timebase_get();

                // log error that calls out firmware and APSS procedure
                // set error severity to l_pcap_sev

                /* @
                 * @errortype
                 * @moduleid    AMEC_SLAVE_CHECK_PERFORMANCE
                 * @reasoncode  PCAP_THROTTLE_POWER_LIMIT
                 * @userdata1   Current Sensor Bulk Power
                 * @userdata2   System PCAP
                 * @userdata4   ERC_AMEC_SLAVE_POWERCAP
                 * @devdesc     Frequency limited due to PowerCap  condition
                 */
                errlHndl_t l_errl = createErrl(AMEC_SLAVE_CHECK_PERFORMANCE, //modId
                                              PCAP_THROTTLE_POWER_LIMIT,     //reasoncode
                                              ERC_AMEC_SLAVE_POWERCAP,       //Extended reason code
                                              l_pcap_sev,                    //Severity
                                              NULL,                          //Trace Buf
                                              DEFAULT_TRACE_SIZE,            //Trace Size
                                              l_snrBulkPwr,                  //userdata1
                                              G_sysConfigData.pcap.system_pcap);//userdata2

                addCalloutToErrl(   l_errl,
                                    ERRL_CALLOUT_TYPE_COMPONENT_ID,
                                    ERRL_COMPONENT_ID_FIRMWARE,
                                    ERRL_CALLOUT_PRIORITY_HIGH
                                );

                addCalloutToErrl(   l_errl,
                                    ERRL_CALLOUT_TYPE_HUID,
                                    G_sysConfigData.apss_huid,
                                    ERRL_CALLOUT_PRIORITY_HIGH
                                );

                // and sets the consolidate action flag
                setErrlActions( l_errl, ERRL_ACTIONS_CONSOLIDATE_ERRORS );

                // then l_pcap_sev to informational
                l_pcap_sev = ERRL_SEV_INFORMATIONAL;

                // Commit Error
                commitErrl(&l_errl);

                // we are done lets break
                break;
            }
        }

        // trottle trace to every 3600 seconds (1hr = 3600000)
        if(!l_throttle_traced && ( DURATION_IN_MS_UNTIL_NOW_FROM(l_time) > 3600000 ) )
        {
            TRAC_INFO("Frequency power limited due to transient condition: PowerLimited=%x, OverSubScription=%x CurrentBulkPwr=%x",
            G_non_dps_power_limited, AMEC_INTF_GET_OVERSUBSCRIPTION(), l_snrBulkPwr );
            l_throttle_traced = TRUE;

            l_time = ssx_timebase_get();
        }
    }
    while( 0 );

    return;
}
Exemple #7
0
// Function Specification
//
// Name: amec_slv_proc_voting_box
//
// Description: Slave OCC's voting box that decides the frequency request.
//              This function will run every tick.
//
// Thread: RealTime Loop
//
// Task Flags:
//
// End Function Specification
void amec_slv_proc_voting_box(void)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    uint16_t                        k = 0;
    uint16_t                        l_chip_fmax = g_amec->sys.fmax;
    uint16_t                        l_core_freq = 0;
    uint16_t                        l_core_freq_max = 0;  // max freq across all cores
    uint16_t                        l_core_freq_min = g_amec->sys.fmax;  // min freq across all cores
    uint32_t                        l_current_reason = 0;  // used for debug purposes
    static uint32_t                 L_last_reason = 0;     // used for debug purposes
    uint32_t                        l_chip_reason = 0;
    uint32_t                        l_core_reason = 0;
    amec_proc_voting_reason_t       l_kvm_throt_reason = NO_THROTTLE;
    amec_part_t                     *l_part = NULL;

    // frequency threshold for reporting throttling
    uint16_t l_report_throttle_freq = G_sysConfigData.system_type.report_dvfs_nom ?  G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL] : G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/
    if (!G_allowPstates)
    {
        // Don't allow pstates to be sent until after initial mode has been set
        if ( (CURRENT_MODE()) || (G_sysConfigData.system_type.kvm) )
        {
            G_allowPstates = TRUE;
        }
    }

    // Voting Box for CPU speed.
    // This function implements the voting box to decide which input gets the right
    // to actuate the system.

    // check for oversubscription if redundant ps policy (oversubscription) is being enforced
    if (G_sysConfigData.system_type.non_redund_ps == false)
    {
        // If in oversubscription and there is a defined (non 0) OVERSUB frequency less than max then use it
        if( (AMEC_INTF_GET_OVERSUBSCRIPTION()) &&
            (G_sysConfigData.sys_mode_freq.table[OCC_MODE_OVERSUB]) &&
            (G_sysConfigData.sys_mode_freq.table[OCC_MODE_OVERSUB] < l_chip_fmax) )
        {
            l_chip_fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_OVERSUB];
            l_chip_reason = AMEC_VOTING_REASON_OVERSUB;
        }
    }

    // If there is an active VRM fault and a defined (non 0) VRM N frequency less than max use it
    if( (g_amec->sys.vrm_fault_status) &&
        (G_sysConfigData.sys_mode_freq.table[OCC_MODE_VRM_N]) &&
        (G_sysConfigData.sys_mode_freq.table[OCC_MODE_VRM_N] < l_chip_fmax) )
    {
        l_chip_fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_VRM_N];
        l_chip_reason = AMEC_VOTING_REASON_VRM_N;
    }

    // PPB_FMAX
    if(g_amec->proc[0].pwr_votes.ppb_fmax < l_chip_fmax)
    {
        l_chip_fmax = g_amec->proc[0].pwr_votes.ppb_fmax;
        l_chip_reason = AMEC_VOTING_REASON_PPB;

        if(l_report_throttle_freq <= l_chip_fmax)
        {
            l_kvm_throt_reason = PCAP_EXCEED_REPORT;
        }
        else
        {
            l_kvm_throt_reason = POWERCAP;
        }
    }

    // PMAX_CLIP_FREQ
    if(g_amec->proc[0].pwr_votes.pmax_clip_freq < l_chip_fmax)
    {
        l_chip_fmax = g_amec->proc[0].pwr_votes.pmax_clip_freq;
        l_chip_reason = AMEC_VOTING_REASON_PMAX;
        l_kvm_throt_reason = POWER_SUPPLY_FAILURE;
    }

    // Pmax_clip frequency request if there is an APSS failure
    if(g_amec->proc[0].pwr_votes.apss_pmax_clip_freq < l_chip_fmax)
    {
        l_chip_fmax = g_amec->proc[0].pwr_votes.apss_pmax_clip_freq;
        l_chip_reason = AMEC_VOTING_REASON_APSS_PMAX;
        l_kvm_throt_reason = POWER_SUPPLY_FAILURE;
    }

    //THERMALPROC.FREQ_REQUEST
    //Thermal controller input based on processor temperature
    if(g_amec->thermalproc.freq_request < l_chip_fmax)
    {
        l_chip_fmax = g_amec->thermalproc.freq_request;
        l_chip_reason = AMEC_VOTING_REASON_PROC_THRM;

        if( l_report_throttle_freq <= l_chip_fmax)
        {
            l_kvm_throt_reason = PROC_OVERTEMP_EXCEED_REPORT;
        }
        else
        {
            l_kvm_throt_reason = CPU_OVERTEMP;
        }
    }

    //Thermal controller input based on VRM Vdd temperature
    if(g_amec->thermalvdd.freq_request < l_chip_fmax)
    {
        l_chip_fmax = g_amec->thermalvdd.freq_request;
        l_chip_reason = AMEC_VOTING_REASON_VDD_THRM;

        if( l_report_throttle_freq <= l_chip_fmax)
        {
            l_kvm_throt_reason = VDD_OVERTEMP_EXCEED_REPORT;
        }
        else
        {
            l_kvm_throt_reason = VDD_OVERTEMP;
        }
    }

    for (k=0; k<MAX_NUM_CORES; k++)
    {
        if( CORE_PRESENT(k) && !CORE_OFFLINE(k) )
        {
            l_core_freq = l_chip_fmax;
            l_core_reason = l_chip_reason;

            // Disable DPS in KVM
            if(!G_sysConfigData.system_type.kvm)
            {
                l_part = amec_part_find_by_core(&g_amec->part_config, k);

                // Check frequency request generated by DPS algorithms
                if(g_amec->proc[0].core[k].core_perf.dps_freq_request < l_core_freq)
                {
                    l_core_freq = g_amec->proc[0].core[k].core_perf.dps_freq_request;
                    l_core_reason = AMEC_VOTING_REASON_UTIL;
                }

                // Adjust frequency based on soft frequency boundaries
                if(l_part != NULL)
                {
                    if(l_core_freq < l_part->soft_fmin)
                    {
                        // Before enforcing a soft Fmin, make sure we don't
                        // have a thermal or power emergency
                        if(!(l_chip_reason & (AMEC_VOTING_REASON_PROC_THRM |
                                              AMEC_VOTING_REASON_VDD_THRM |
                                              AMEC_VOTING_REASON_PPB |
                                              AMEC_VOTING_REASON_PMAX |
                                              AMEC_VOTING_REASON_CONN_OC)))
                        {
                            l_core_freq = l_part->soft_fmin;
                            l_core_reason = AMEC_VOTING_REASON_SOFT_MIN;
                        }
                    }
                    else if(l_core_freq > l_part->soft_fmax)
                    {
                        l_core_freq = l_part->soft_fmax;
                        l_core_reason = AMEC_VOTING_REASON_SOFT_MAX;
                    }
                }
            }

            if(CURRENT_MODE() == OCC_MODE_NOMINAL)
            {
                // PROC_PCAP_NOM_VOTE
                if(g_amec->proc[0].pwr_votes.proc_pcap_nom_vote < l_core_freq)
                {
                    l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_nom_vote;
                    l_core_reason = AMEC_VOTING_REASON_PWR;
                    l_kvm_throt_reason = POWERCAP;
                }
            }
            else
            {
                // PROC_PCAP_VOTE
                if(g_amec->proc[0].pwr_votes.proc_pcap_vote < l_core_freq)
                {
                    l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_vote;
                    l_core_reason = AMEC_VOTING_REASON_PWR;

                    if(l_report_throttle_freq <= l_core_freq)
                    {
                        l_kvm_throt_reason = PCAP_EXCEED_REPORT;
                    }
                    else
                    {
                        l_kvm_throt_reason = POWERCAP;
                    }
                }
            }

            // Check IPS frequency request sent by Master OCC
            if(g_amec->slv_ips_freq_request != 0)
            {
                if(g_amec->slv_ips_freq_request < l_core_freq)
                {
                    l_core_freq = g_amec->slv_ips_freq_request;
                    l_core_reason = AMEC_VOTING_REASON_IPS;
                }
            }

            // Override frequency with request from Master OCC
            if(g_amec->foverride_enable)
            {
                if(g_amec->foverride != 0)
                {
                    // Override the frequency on all cores if Master OCC sends
                    // a non-zero request
                    l_core_freq = g_amec->foverride;
                    l_core_reason = AMEC_VOTING_REASON_OVERRIDE;
                }

                l_kvm_throt_reason = MANUFACTURING_OVERRIDE;
            }

            if(g_amec->pstate_foverride_enable)
            {
                if(g_amec->pstate_foverride != 0)
                {
                    // Override the frequency on all cores if the Global Pstate
                    // table has been modified
                    l_core_freq = g_amec->pstate_foverride;
                    l_core_reason = AMEC_VOTING_REASON_OVERRIDE;
                }
            }

            //Make sure the frequency is not less then the system min
            if(l_core_freq < g_amec->sys.fmin)
            {
                l_core_freq = g_amec->sys.fmin;
            }

            // Override frequency via Amester parameter interface
            if (g_amec->proc[0].parm_f_override_enable &&
                g_amec->proc[0].parm_f_override[k] > 0)
            {
                l_core_freq = g_amec->proc[0].parm_f_override[k];
                l_core_reason = AMEC_VOTING_REASON_OVERRIDE_CORE;
            }

            //STORE core frequency and reason
            g_amec->proc[0].core[k].f_request = l_core_freq;
            g_amec->proc[0].core[k].f_reason = l_core_reason;
            if(l_core_freq < l_core_freq_min)
            {
                // store the new lowest frequency and reason to be used after all cores checked
                l_core_freq_min = l_core_freq;
                l_current_reason = l_core_reason;
            }

            // Update the Amester parameter telling us the reason. Needed for
            // parameter array.
            g_amec->proc[0].parm_f_reason[k] = l_core_reason;

            //CURRENT_MODE() may be OCC_MODE_NOCHANGE because STATE change is processed
            //before MODE change
            if ((CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE)    &&
                (CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE_FP) &&
                (CURRENT_MODE() != OCC_MODE_NOM_PERFORMANCE)   &&
                (CURRENT_MODE() != OCC_MODE_MAX_PERFORMANCE)   &&
                (CURRENT_MODE() != OCC_MODE_FMF)               &&
                (CURRENT_MODE() != OCC_MODE_NOCHANGE)          &&
                (l_core_reason & NON_DPS_POWER_LIMITED))
            {
                G_non_dps_power_limited = TRUE;
            }
            else
            {
                G_non_dps_power_limited = FALSE;
            }

            // Update the sensor telling us what the requested frequency is
            sensor_update( AMECSENSOR_ARRAY_PTR(FREQREQC0,k),
                    (uint16_t) g_amec->proc[0].core[k].f_request);

#if DEBUG_PROC_VOTING_BOX
            /// This trace that can be used to debug the voting
            /// box and control loops.  It will trace the reason why a
            /// controller is lowering the freq, but will only do it once in a
            /// row for the specific freq it wants to control to.  It assumes
            /// that all cores will be controlled to same freq.
            if(l_chip_fmax != g_amec->sys.fmax){
                static uint16_t L_trace = 0;
                if(l_chip_fmax != L_trace){
                    L_trace = l_chip_fmax;
                    TRAC_INFO("Core: %d, Freq: %d, Reason: %d",k,l_core_freq,l_core_reason);
                }
            }
#endif

            if(l_core_freq > l_core_freq_max)
            {
                l_core_freq_max = l_core_freq;
            }
        } // if core present and not offline
        else
        {
            //Set f_request to 0 so this core is ignored in amec_slv_freq_smh()
            g_amec->proc[0].core[k].f_request = 0;
            g_amec->proc[0].core[k].f_reason = 0;
        }
    }//End of for loop

    // update max core frequency if not 0 i.e. all cores offline (stop 2 or greater)
    // this is used by power capping alg, updating to 0 will cause power throttling when not needed
    if(l_core_freq_max)
    {
        g_amec->proc[0].core_max_freq = l_core_freq_max;
        // update the overall reason driving frequency across all cores
        g_amec->proc[0].f_reason = l_current_reason;
    }

    //check if there was a throttle reason change
    if(l_kvm_throt_reason != G_amec_opal_proc_throt_reason)
    {
        //Always update G_amec_opal_proc_throt_reason, this is used to set poll rsp bits for all system types
        G_amec_opal_proc_throt_reason = l_kvm_throt_reason;

        // Only if running OPAL need to notify dcom thread to update the table in HOMER for OPAL
        if(G_sysConfigData.system_type.kvm)
        {
            ssx_semaphore_post(&G_dcomThreadWakeupSem);
        }
    }
    // For debug... if lower than max update vars returned in poll response to give clipping reason
    g_amec->proc[0].core_min_freq = l_core_freq_min;
    if(l_core_freq_min < g_amec->sys.fmax)
    {
        if(l_current_reason == L_last_reason)
        {
            // same reason INC counter
            if(g_amec->proc[0].current_clip_count != 0xFF)
            {
                 g_amec->proc[0].current_clip_count++;
            }
        }
        else
        {
            // new reason update history and set counter to 1
            L_last_reason = l_current_reason;
            g_amec->proc[0].current_clip_count = 1;
            if( (g_amec->proc[0].chip_f_reason_history & l_current_reason) == 0)
            {
                g_amec->proc[0].chip_f_reason_history |= l_current_reason;
                TRAC_IMP("First time throttling for reason[0x%08X] History[0x%08X] freq = %d",
                          l_current_reason, g_amec->proc[0].chip_f_reason_history, l_core_freq_min);
            }
        }
    }
    else // no active clipping
    {
        L_last_reason = 0;
        g_amec->proc[0].current_clip_count = 0;
    }
}
Exemple #8
0
// Function Specification
//
// Name: amec_slv_freq_smh
//
// Description: Slave OCC's frequency state machine.
//              This function will run every tick.
//
// Thread: RealTime Loop
//
// Task Flags:
//
// End Function Specification
void amec_slv_freq_smh(void)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    uint8_t     quad = 0;       // loop through quads
    uint8_t     core_num = 0;   // core ID
    uint8_t     core_idx = 0;   // loop through cores within each quad
    Pstate      pmax[MAXIMUM_QUADS] = {0}; // max pstate (min frequency) within each quad
    Pstate      pmax_chip = 0;  // highest Pstate (lowest frequency) across all quads
    bool        l_atLeast1Core[MAXIMUM_QUADS] = {FALSE};  // at least 1 core present and online in quad
    bool        l_atLeast1Quad = FALSE;    // at least 1 quad online
    static bool L_mfg_set_trace[MAXIMUM_QUADS] = {FALSE};
    static bool L_mfg_clear_trace[MAXIMUM_QUADS] = {FALSE};

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/

    // loop through all quads, get f_requests, translate to pstates and determine pmax across chip
    for (quad = 0; quad < MAXIMUM_QUADS; quad++)
    {
        for (core_idx=0; core_idx<NUM_CORES_PER_QUAD; core_idx++)  // loop thru all cores in quad
        {
            core_num = (quad*NUM_CORES_PER_QUAD) + core_idx;

            // ignore core if freq request is 0 (core not present when amec_slv_proc_voting_box ran)
            if(g_amec->proc[0].core[core_num].f_request != 0)
            {
               l_atLeast1Core[quad] = TRUE;
               l_atLeast1Quad = TRUE;
               // The higher the pstate number, the lower the frequency
               if(pmax[quad] <  proc_freq2pstate(g_amec->proc[0].core[core_num].f_request))
               {
                   pmax[quad] = proc_freq2pstate(g_amec->proc[0].core[core_num].f_request);
                   if(pmax_chip < pmax[quad])  // check if this is a new lowest freq for the chip
                      pmax_chip = pmax[quad];
               }
            }
        }
    }

    // Skip determining new frequency if all cores in all quads are offline
    if(l_atLeast1Quad)
    {
        // check for mfg quad Pstate request and set Pstate for each quad
        for (quad = 0; quad < MAXIMUM_QUADS; quad++)
        {
            // set quad with no cores present to lowest frequency for the chip
            if(l_atLeast1Core[quad] == FALSE)
               pmax[quad] = pmax_chip;

            // check if there is a mnfg Pstate request for this quad
            if(g_amec->mnfg_parms.quad_pstate[quad] != 0xFF)
            {
               // use mnfg request if it is a lower frequency (higher pState)
               if(g_amec->mnfg_parms.quad_pstate[quad] > pmax[quad])
                  pmax[quad] = g_amec->mnfg_parms.quad_pstate[quad];

               if(L_mfg_clear_trace[quad] == FALSE)
                  L_mfg_set_trace[quad] = TRUE;
            }
            else if(L_mfg_clear_trace[quad] == TRUE)
            {
                TRAC_INFO("amec_slv_freq_smh: mfg Quad %d Pstate request cleared. New Pstate = 0x%02x", quad, pmax[quad]);
                L_mfg_clear_trace[quad] = FALSE;
            }

#ifdef PROC_DEBUG
            if (G_desired_pstate[quad] != pmax[quad])
            {
                TRAC_IMP("Updating Quad %d's Pstate to %d", quad, pmax[quad]);
            }
#endif
            // update quad pstate request
            G_desired_pstate[quad] = pmax[quad];

            if(L_mfg_set_trace[quad] == TRUE)
            {
                TRAC_INFO("amec_slv_freq_smh: mfg Quad %d Pstate request set = 0x%02x", quad, pmax[quad]);
                L_mfg_set_trace[quad] = FALSE;
                L_mfg_clear_trace[quad] = TRUE;
            }
        }
    }  // if at least 1 core online
}
Exemple #9
0
// Function Specification
//
// Name: amec_set_freq_range
//
// Description: Set the frequency range for AMEC based on mode only
//              NOTE:  Any other clipping of frequency should be done in
//                     amec_slv_proc_voting_box() (called every tick)
//                     so the CLIP history in poll response will accurately
//                     show all clipping for the given mode the system is in
//              This function will run on mode changes and cnfg_data changes
//
// Thread: RealTime Loop
//
// Task Flags:
//
// End Function Specification
errlHndl_t amec_set_freq_range(const OCC_MODE i_mode)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    errlHndl_t                  l_err = NULL;
    uint16_t                    l_freq_min  = 0;
    uint16_t                    l_freq_max  = 0;
    uint32_t                    l_temp = 0;
    amec_mode_freq_t            l_ppm_freq[OCC_INTERNAL_MODE_MAX_NUM] = {{0}};

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/

    // First set to Max Freq Range for this mode
    // if no mode set yet default to the full range
    if(i_mode == OCC_MODE_NOCHANGE)
    {
        l_freq_min = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];

        // Set Max frequency (turbo if wof off, otherwise max possible (ultra turbo)
        if( g_amec->wof.wof_disabled || (g_amec->wof.wof_init_state != WOF_ENABLED))
        {
            l_freq_max = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
        }
        else
        {
            l_freq_max = G_proc_fmax_mhz;
        }
    }
    else if( VALID_MODE(i_mode) )  // Set to Max Freq Range for this mode
    {
      l_freq_min = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];

      // Use max frequency for performance modes and FMF
      if( (i_mode == OCC_MODE_NOM_PERFORMANCE) || (i_mode == OCC_MODE_MAX_PERFORMANCE) ||
          (i_mode == OCC_MODE_FMF) || (i_mode == OCC_MODE_DYN_POWER_SAVE) ||
          (i_mode == OCC_MODE_DYN_POWER_SAVE_FP) )
      {
          // clip to turbo if WOF is disabled
          if( g_amec->wof.wof_disabled || (g_amec->wof.wof_init_state != WOF_ENABLED))
          {
              l_freq_max = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
          }
          else
          {
              l_freq_max = G_proc_fmax_mhz;
          }
      }
      else
      {
          l_freq_max = G_sysConfigData.sys_mode_freq.table[i_mode];
      }
    }

    if( (l_freq_min == 0) || (l_freq_max == 0) )
    {
      // Do not update amec vars with a 0 frequency.
      // The frequency limit for each mode should have been set prior
      // to calling or the mode passed was invalid
      TRAC_ERR("amec_set_freq_range: Freq of 0 found! mode[0x%02x] Fmin[%u] Fmax[%u]",
                  i_mode,
                  l_freq_min,
                  l_freq_max);

      // Log an error if this is PowerVM as this should never happen when OCC
      // supports modes
      if(!G_sysConfigData.system_type.kvm)
      {
        /* @
         * @errortype
         * @moduleid    AMEC_SET_FREQ_RANGE
         * @reasoncode  INTERNAL_FW_FAILURE
         * @userdata1   Mode
         * @userdata2   0
         * @userdata4   ERC_FW_ZERO_FREQ_LIMIT
         * @devdesc     Fmin or Fmax of 0 found for mode
         */
         errlHndl_t l_err = createErrl(AMEC_SET_FREQ_RANGE,           //modId
                                       INTERNAL_FW_FAILURE,           //reasoncode
                                       ERC_FW_ZERO_FREQ_LIMIT,        //Extended reason code
                                       ERRL_SEV_PREDICTIVE,           //Severity
                                       NULL,                          //Trace Buf
                                       DEFAULT_TRACE_SIZE,            //Trace Size
                                       i_mode,                        //userdata1
                                       0);                            //userdata2

         // Callout Firmware
         addCalloutToErrl(l_err,
                          ERRL_CALLOUT_TYPE_COMPONENT_ID,
                          ERRL_COMPONENT_ID_FIRMWARE,
                          ERRL_CALLOUT_PRIORITY_LOW
                          );
      }
    }
    else
    {
      g_amec->sys.fmin = l_freq_min;
      g_amec->sys.fmax = l_freq_max;

      TRAC_INFO("amec_set_freq_range: Mode[0x%02x] Fmin[%u] (Pmin 0x%02x) Fmax[%u] (Pmax 0x%02x)",
                i_mode,
                l_freq_min,
                proc_freq2pstate(g_amec->sys.fmin),
                l_freq_max,
                proc_freq2pstate(g_amec->sys.fmax));

      // Now determine the max frequency for the PPM structure
      l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmax    = G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL];
      l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax    = G_sysConfigData.sys_mode_freq.table[OCC_MODE_DYN_POWER_SAVE];
      l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_DYN_POWER_SAVE_FP];

      // Determine the min frequency for the PPM structure. This Fmin should
      // always be set to the system Fmin
      l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmin    = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
      l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmin    = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
      l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];

      // Determine the min speed allowed for DPS power policies (this is needed
      // by the DPS algorithms)
      l_temp = (l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmin * 1000)/l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax;
      l_ppm_freq[OCC_INTERNAL_MODE_DPS].min_speed = l_temp;

      l_temp = (l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmin * 1000)/l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmax;
      l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].min_speed = l_temp;

      // Copy the PPM frequency information into g_amec
      memcpy(g_amec->part_mode_freq, l_ppm_freq, sizeof(l_ppm_freq));

    }
    return l_err;
}
Exemple #10
0
// Function Specification
//
// Name: amec_slv_freq_smh
//
// Description: Slave OCC's voting box that decides the memory speed request.
//              This function will run every tick.
//
// Thread: RealTime Loop
//
// Task Flags:
//
// End Function Specification
void amec_slv_mem_voting_box(void)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    UINT16                  l_vote;
    UINT8                   l_reason;
    static INT16            l_slew_step = AMEC_MEMORY_STEP_SIZE;
    static bool             L_throttle_traced = FALSE;

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/

    // Start with max allowed speed
    l_vote = AMEC_MEMORY_MAX_STEP;
    l_reason = AMEC_MEM_VOTING_REASON_INIT;

    // Check vote from Centaur thermal control loop
    if (l_vote > g_amec->thermalcent.speed_request)
    {
        l_vote = g_amec->thermalcent.speed_request;
        l_reason = AMEC_MEM_VOTING_REASON_CENT;
    }

    // Check vote from DIMM thermal control loop
    if (l_vote > g_amec->thermaldimm.speed_request)
    {
        l_vote = g_amec->thermaldimm.speed_request;
        l_reason = AMEC_MEM_VOTING_REASON_DIMM;
    }

    // Check if memory autoslewing is enabled
    if (g_amec->mnfg_parms.mem_autoslew)
    {
        //check if we've reached the max setting and need to start going down
        if(g_amec->mem_speed_request >= AMEC_MEMORY_MAX_STEP)
        {
            g_amec->mnfg_parms.mem_slew_counter++;
            l_slew_step = -AMEC_MEMORY_STEP_SIZE;
        }

        //check if we've reached the min setting and need to start going up
        else if(g_amec->mem_speed_request <= AMEC_MEMORY_MIN_STEP)
        {
            g_amec->mnfg_parms.mem_slew_counter++;
            l_slew_step = AMEC_MEMORY_STEP_SIZE;
        }

        l_vote = g_amec->mem_speed_request + l_slew_step;
        l_reason = AMEC_MEM_VOTING_REASON_SLEW;
    }

    // Store final vote and vote reason in g_amec
    g_amec->mem_throttle_reason = l_reason;
    g_amec->mem_speed_request = l_vote;

    //trace changes in memory throttling
    if(l_reason != AMEC_MEM_VOTING_REASON_INIT)
    {
        if(!L_throttle_traced)
        {
            L_throttle_traced = TRUE;
            TRAC_INFO("Memory is being throttled. reason[%d] vote[%d] cent_expired[0x%02x] dimm_expired[0x%02x]",
                       l_reason,
                       l_vote,
                       G_cent_temp_expired_bitmap,
                       G_dimm_temp_expired_bitmap);
        }
    }
    else
    {
        if(L_throttle_traced)
        {
            L_throttle_traced = FALSE;
            TRAC_INFO("Memory is no longer being throttled");
        }
    }
    return;
}
Exemple #11
0
// Function Specification
//
// Name: amec_slv_voting_box
//
// Description: Slave OCC's voting box that decides the frequency request.
//              This function will run every tick.
//
// Thread: RealTime Loop
//
// Task Flags:
//
// End Function Specification
void amec_slv_voting_box(void)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    uint16_t                        k = 0;
    uint16_t                        l_chip_fmax = g_amec->sys.fmax;
    uint16_t                        l_core_freq = 0;
    uint32_t                        l_chip_reason = 0;
    uint32_t                        l_core_reason = 0;
    uint8_t                         l_kvm_throt_reason = NO_THROTTLE;
    amec_part_t                     *l_part = NULL;
    bool                            l_freq_req_changed = FALSE;

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/

    // Voting Box for CPU speed.
    // This function implements the voting box to decide which input gets the right
    // to actuate the system.

    //Reset the maximum core frequency requested prior to recalculation.
    g_amec->proc[0].core_max_freq = 0;

    // PPB_FMAX
    if(g_amec->proc[0].pwr_votes.ppb_fmax < l_chip_fmax)
    {
        l_chip_fmax = g_amec->proc[0].pwr_votes.ppb_fmax;
        l_chip_reason = AMEC_VOTING_REASON_PPB;
        l_kvm_throt_reason = POWERCAP;
    }

    // PMAX_CLIP_FREQ
    if(g_amec->proc[0].pwr_votes.pmax_clip_freq < l_chip_fmax)
    {
        l_chip_fmax = g_amec->proc[0].pwr_votes.pmax_clip_freq;
        l_chip_reason = AMEC_VOTING_REASON_PMAX;
        l_kvm_throt_reason = POWER_SUPPLY_FAILURE;
    }

    //THERMALPROC.FREQ_REQUEST
    //Thermal controller input based on processor temperature
    if(g_amec->thermalproc.freq_request < l_chip_fmax)
    {
        l_chip_fmax = g_amec->thermalproc.freq_request;
        l_chip_reason = AMEC_VOTING_REASON_PROC_THRM;
        l_kvm_throt_reason = CPU_OVERTEMP;
    }

    // Controller request based on VRHOT signal from processor regulator
    if(g_amec->vrhotproc.freq_request < l_chip_fmax)
    {
        l_chip_fmax = g_amec->vrhotproc.freq_request;
        l_chip_reason = AMEC_VOTING_REASON_VRHOT_THRM;
        l_kvm_throt_reason = CPU_OVERTEMP;
    }

    // CONN_OC_VOTE
    if(g_amec->proc[0].pwr_votes.conn_oc_vote < l_chip_fmax)
    {
        l_chip_fmax = g_amec->proc[0].pwr_votes.conn_oc_vote;
        l_chip_reason = AMEC_VOTING_REASON_CONN_OC;
        l_kvm_throt_reason = OVERCURRENT;
    }

    for (k=0; k<MAX_NUM_CORES; k++)
    {
        if(CORE_PRESENT(k))
        {
            l_core_freq = l_chip_fmax;
            l_core_reason = l_chip_reason;

            // Disable DPS in KVM
            if(!G_sysConfigData.system_type.kvm)
            {
                l_part = amec_part_find_by_core(&g_amec->part_config, k);

                // Check frequency request generated by DPS algorithms
                if(g_amec->proc[0].core[k].core_perf.dps_freq_request < l_core_freq)
                {
                    l_core_freq = g_amec->proc[0].core[k].core_perf.dps_freq_request;
                    l_core_reason = AMEC_VOTING_REASON_UTIL;
                }

                // Adjust frequency based on soft frequency boundaries
                if(l_part != NULL)
                {
                    if(l_core_freq < l_part->soft_fmin)
                    {
                        // Before enforcing a soft Fmin, make sure we don't
                        // have a thermal or power emergency
                        if(!(l_chip_reason & (AMEC_VOTING_REASON_PROC_THRM |
                                              AMEC_VOTING_REASON_VRHOT_THRM |
                                              AMEC_VOTING_REASON_PPB |
                                              AMEC_VOTING_REASON_PMAX |
                                              AMEC_VOTING_REASON_CONN_OC)))
                        {
                            l_core_freq = l_part->soft_fmin;
                            l_core_reason = AMEC_VOTING_REASON_SOFT_MIN;
                        }
                    }
                    else if(l_core_freq > l_part->soft_fmax)
                    {
                        l_core_freq = l_part->soft_fmax;
                        l_core_reason = AMEC_VOTING_REASON_SOFT_MAX;
                    }
                }
            }

            if(CURRENT_MODE() == OCC_MODE_NOMINAL)
            {
                // PROC_PCAP_NOM_VOTE
                if(g_amec->proc[0].pwr_votes.proc_pcap_nom_vote < l_core_freq)
                {
                    l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_nom_vote;
                    l_core_reason = AMEC_VOTING_REASON_PWR;
                    l_kvm_throt_reason = POWERCAP;
                }
            }
            else
            {
                // PROC_PCAP_VOTE
                if(g_amec->proc[0].pwr_votes.proc_pcap_vote < l_core_freq)
                {
                    l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_vote;
                    l_core_reason = AMEC_VOTING_REASON_PWR;
                    l_kvm_throt_reason = POWERCAP;
                }
            }

            // Check IPS frequency request sent by Master OCC
            if(g_amec->slv_ips_freq_request != 0)
            {
                if(g_amec->slv_ips_freq_request < l_core_freq)
                {
                    l_core_freq = g_amec->slv_ips_freq_request;
                    l_core_reason = AMEC_VOTING_REASON_IPS;
                }
            }

            // Override frequency with request from Master OCC
            if(g_amec->foverride_enable)
            {
                if(g_amec->foverride != 0)
                {
                    // Override the frequency on all cores if Master OCC sends
                    // a non-zero request
                    l_core_freq = g_amec->foverride;
                    l_core_reason = AMEC_VOTING_REASON_OVERRIDE;
                }
            }

            //Make sure the frequency is not less then the system min
            if(l_core_freq < g_amec->sys.fmin)
            {
                l_core_freq = g_amec->sys.fmin;
            }

            // Override frequency via Amester parameter interface
            if (g_amec->proc[0].parm_f_override_enable &&
                g_amec->proc[0].parm_f_override[k] > 0)
            {
                l_core_freq = g_amec->proc[0].parm_f_override[k];
                l_core_reason = AMEC_VOTING_REASON_OVERRIDE_CORE;
            }

            // If frequency has changed, set the flag
            if ( (l_core_freq != g_amec->proc[0].core[k].f_request) ||
                    (l_core_freq != g_amec->sys.fmax))
            {
                l_freq_req_changed = TRUE;
            }

            //STORE core frequency and reason
            g_amec->proc[0].core[k].f_request = l_core_freq;
            g_amec->proc[0].core[k].f_reason = l_core_reason;

            // Update the Amester parameter telling us the reason. Needed for
            // parameter array.
            g_amec->proc[0].parm_f_reason[k] = l_core_reason;

            //CURRENT_MODE() may be OCC_MODE_NOCHANGE because STATE change is processed
            //before MODE change
            if ((CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE) &&
                (CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE_FP) &&
                (CURRENT_MODE() != OCC_MODE_NOCHANGE) &&
                (l_core_reason & NON_DPS_POWER_LIMITED))
            {
                G_non_dps_power_limited = TRUE;
            }
            else
            {
                G_non_dps_power_limited = FALSE;
            }

            // Update the sensor telling us what the requested frequency is
            sensor_update( AMECSENSOR_ARRAY_PTR(FREQ250USP0C0,k),
                    (uint16_t) g_amec->proc[0].core[k].f_request);

#if 0
            /// TODO: This can be deleted if deemed useless
            /// This trace that can be used to debug the voting
            /// box an control loops.  It will trace the reason why a
            /// controller is lowering the freq, but will only do it once in a
            /// row for the specific freq it wants to control to.  It assumes
            /// that all cores will be controlled to same freq.
            if(l_chip_fmax != g_amec->sys.fmax){
                static uint16_t L_trace = 0;
                if(l_chip_fmax != L_trace){
                    L_trace = l_chip_fmax;
                    TRAC_INFO("Core: %d, Freq: %d, Reason: %d",k,l_core_freq,l_core_reason);
                }
            }
#endif

            if(l_core_freq > g_amec->proc[0].core_max_freq)
            {
                g_amec->proc[0].core_max_freq = l_core_freq;
            }
        }
        else
        {
            l_core_freq = 0;
            l_core_reason = 0;
        }
    }//End of for loop

    // Check if the frequency is going to be changing
    if( l_freq_req_changed == TRUE )
    {
        G_time_until_freq_check = FREQ_CHG_CHECK_TIME;
    }
    else if (G_time_until_freq_check != 0)
    {
        G_time_until_freq_check--;
    }

    //convert POWERCAP reason to POWER_SUPPLY_FAILURE if ovs/failsafe is asserted
    if((l_kvm_throt_reason == POWERCAP) &&
        (AMEC_INTF_GET_FAILSAFE() || AMEC_INTF_GET_OVERSUBSCRIPTION()))
    {
        l_kvm_throt_reason = POWER_SUPPLY_FAILURE;
    }

    //check if we need to update the throttle reason in homer
    if(G_sysConfigData.system_type.kvm &&
       (l_kvm_throt_reason != G_amec_kvm_throt_reason))
    {
        //Notify dcom thread to update the table
        G_amec_kvm_throt_reason = l_kvm_throt_reason;
        ssx_semaphore_post(&G_dcomThreadWakeupSem);
    }
}
Exemple #12
0
// Function Specification
//
// Name: amec_set_freq_range
//
// Description: Set the frequency range for AMEC
//              This function will run on mode changes and cnfg_data changes
//
// Thread: RealTime Loop
//
// Task Flags:
//
// End Function Specification
errlHndl_t amec_set_freq_range(const OCC_MODE i_mode)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    errlHndl_t                  l_err = NULL;
    uint16_t                    l_freq_min  = 0;
    uint16_t                    l_freq_max  = 0;
    uint32_t                    l_temp = 0;
    amec_mode_freq_t            l_ppm_freq[OCC_INTERNAL_MODE_MAX_NUM] = {{0}};

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/

    // First set to Max Freq Range for this mode
    if( VALID_MODE(i_mode) )
    {
      l_freq_min = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
      l_freq_max = G_sysConfigData.sys_mode_freq.table[i_mode];
    }

    // If SMS is set then TMGT wants us to pin to frequency which
    // corresponds to input mode.  They will use this function
    // when powering off and they wish to have us bring the system
    // back up to real nominal frequency (without being impacted
    // by power caps or thermal actuations)
    if(CURRENT_SMS() == SMGR_SMS_STATIC_VF_CHANGE_REQ)
    {
        l_freq_min = l_freq_max;
    }

    g_amec->sys.fmin = l_freq_min;
    g_amec->sys.fmax = l_freq_max;

    TRAC_INFO("amec_set_freq_range: Mode[0x%02x] Fmin[%u] Fmax[%u]",
              i_mode,
              l_freq_min,
              l_freq_max);

    // Now determine the max frequency for the PPM structure
    l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmax    = G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL];
    l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax    = G_sysConfigData.sys_mode_freq.table[OCC_MODE_DYN_POWER_SAVE];
    l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_DYN_POWER_SAVE_FP];

    // Determine the min frequency for the PPM structure. This Fmin should
    // always be set to the system Fmin
    l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmin    = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
    l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmin    = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
    l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];

    // Determine the min speed allowed for DPS power policies (this is needed
    // by the DPS algorithms)
    l_temp = (l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmin * 1000)/l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax;
    l_ppm_freq[OCC_INTERNAL_MODE_DPS].min_speed = l_temp;

    l_temp = (l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmin * 1000)/l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmax;
    l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].min_speed = l_temp;

    // Copy the PPM frequency information into g_amec
    memcpy(g_amec->part_mode_freq, l_ppm_freq, sizeof(l_ppm_freq));

    TRAC_INFO("amec_set_freq_range: PPM Fmin[%u] Fnom[%u] Fmax[%u] min_speed[%u]",
              l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmin,
              l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmax,
              l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax,
              l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].min_speed);

    return l_err;
}
Exemple #13
0
void amec_update_fw_sensors(void)
{
    errlHndl_t l_err                = NULL;
    int rc                          = 0;
    int rc2                         = 0;
    static bool l_first_call        = TRUE;
    bool l_gpe0_idle, l_gpe1_idle;
    static int L_consec_trace_count = 0;

    // ------------------------------------------------------
    // Update OCC Firmware Sensors from last tick
    // ------------------------------------------------------
    int l_last_state = G_fw_timing.amess_state;
    // RTLtickdur    = duration of last tick's RTL ISR (max = 250us)
    sensor_update( AMECSENSOR_PTR(RTLtickdur), G_fw_timing.rtl_dur);
    // AMEintdur     = duration of last tick's AMEC portion of RTL ISR
    sensor_update( AMECSENSOR_PTR(AMEintdur), G_fw_timing.ameint_dur);
    // AMESSdurX     = duration of last tick's AMEC state
    if(l_last_state >= NUM_AMEC_SMH_STATES)
    {
        // Sanity check.  Trace this out, even though it should never happen.
        TRAC_INFO("AMEC State Invalid, Sensor Not Updated");
    }
    else
    {
        // AMESSdurX = duration of last tick's AMEC state
        sensor_update( AMECSENSOR_ARRAY_PTR(AMESSdur0, l_last_state),  G_fw_timing.amess_dur);
    }

    // ------------------------------------------------------
    // Kick off GPE programs to track WorstCase time in GPE
    // and update the sensors.
    // ------------------------------------------------------
    if( (NULL != G_fw_timing.gpe0_timing_request)
        && (NULL != G_fw_timing.gpe1_timing_request) )
    {
        //Check if both GPE engines were able to complete the last GPE job on
        //the queue within 1 tick.
        l_gpe0_idle = async_request_is_idle(&G_fw_timing.gpe0_timing_request->request);
        l_gpe1_idle = async_request_is_idle(&G_fw_timing.gpe1_timing_request->request);
        if(l_gpe0_idle && l_gpe1_idle)
        {
            //reset the consecutive trace count
            L_consec_trace_count = 0;

            //Both GPE engines finished on time. Now check if they were
            //successful too.
            if( async_request_completed(&(G_fw_timing.gpe0_timing_request->request))
                && async_request_completed(&(G_fw_timing.gpe1_timing_request->request)) )
            {
                // GPEtickdur0 = duration of last tick's PORE-GPE0 duration
                sensor_update( AMECSENSOR_PTR(GPEtickdur0), G_fw_timing.gpe_dur[0]);
                // GPEtickdur1 = duration of last tick's PORE-GPE1 duration
                sensor_update( AMECSENSOR_PTR(GPEtickdur1), G_fw_timing.gpe_dur[1]);
            }
            else
            {
                //This case is expected on the first call of the function.
                //After that, this should not happen.
                if(!l_first_call)
                {
                    //Note: FFDC for this case is gathered by each task
                    //responsible for a GPE job.
                    TRAC_INFO("GPE task idle but GPE task did not complete");
                }
                l_first_call = FALSE;
            }

            // Update Time used to measure GPE duration.
            G_fw_timing.rtl_start_gpe = G_fw_timing.rtl_start;

            // Schedule the GPE Routines that will run and update the worst
            // case timings (via callback) after they complete.  These GPE
            // routines are the last GPE routines added to the queue
            // during the RTL tick.
            rc  = pore_flex_schedule(G_fw_timing.gpe0_timing_request);
            rc2 = pore_flex_schedule(G_fw_timing.gpe1_timing_request);

            if(rc || rc2)
            {
                /* @
                 * @errortype
                 * @moduleid    AMEC_UPDATE_FW_SENSORS
                 * @reasoncode  SSX_GENERIC_FAILURE
                 * @userdata1   return code - gpe0
                 * @userdata2   return code - gpe1
                 * @userdata4   OCC_NO_EXTENDED_RC
                 * @devdesc     Failure to schedule PORE-GPE poreFlex object for FW timing
                 *              analysis.
                 */
                l_err = createErrl(
                    AMEC_UPDATE_FW_SENSORS,             //modId
                    SSX_GENERIC_FAILURE,                //reasoncode
                    OCC_NO_EXTENDED_RC,                 //Extended reason code
                    ERRL_SEV_INFORMATIONAL,             //Severity
                    NULL,                               //Trace Buf
                    DEFAULT_TRACE_SIZE,                 //Trace Size
                    rc,                                 //userdata1
                    rc2);                               //userdata2

                // commit error log
                commitErrl( &l_err );
            }
        }
        else if(L_consec_trace_count < MAX_CONSEC_TRACE)
        {
            uint64_t l_dbg1;

            // Reset will eventually be requested due to not having power measurement
            // data after X ticks, but add some additional FFDC to the trace that
            // will tell us what GPE job is currently executing.
            if(!l_gpe0_idle)
            {
                l_dbg1 = in64(PORE_GPE0_DBG1);
                TRAC_ERR("GPE0 programs did not complete within one tick. DBG1[0x%08x%08x]",
                          l_dbg1 >> 32,
                          l_dbg1 & 0x00000000ffffffffull);
            }