Example #1
0
//*************************************************************************
// Functions
//*************************************************************************
int traceSemTest(void)
{
    UINT l_rc = 0;

    // lock trace semaphore first
    l_rc = ssx_semaphore_pend(&g_trac_mutex, TRAC_INTF_MUTEX_TIMEOUT);
    if(SSX_OK == l_rc)
    {
        // create one trace
        TRAC_INFO("traceTest Applet: test trace semaphore");

        // Unlock trace semaphore
        ssx_semaphore_post(&g_trac_mutex);

    }
    else
    {
        l_rc = 1;
    }

    return l_rc;
}
Example #2
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;
    }

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

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

            // 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);
    }
}
Example #3
0
// Function Specification
//
// Name: SMGR_set_mode
//
// Description:
//
// End Function Specification
errlHndl_t SMGR_set_mode(const OCC_MODE i_mode,
                         const uint8_t i_sms_type)
{
     errlHndl_t  l_errlHndl = NULL;
     int         jj=0;
     OCC_MODE l_mode = i_mode;

     do
     {
         // Get lock for critical section
         if(ssx_semaphore_pend(&G_smgrModeChangeSem,SSX_WAIT_FOREVER))
         {
            /* @
             * @errortype
             * @moduleid    MAIN_MODE_TRANSITION_MID
             * @reasoncode  SSX_GENERIC_FAILURE
             * @userdata1   none
             * @userdata4   ERC_RUNNING_SEM_PENDING_FAILURE
             * @devdesc     SSX semaphore related failure
             */
             l_errlHndl = createErrl(MAIN_MODE_TRANSITION_MID,          //modId
                                        SSX_GENERIC_FAILURE,            //reasoncode
                                        ERC_RUNNING_SEM_PENDING_FAILURE,//Extended reason code
                                        ERRL_SEV_UNRECOVERABLE,         //Severity
                                        NULL,                           //Trace Buf
                                        DEFAULT_TRACE_SIZE,             //Trace Size
                                        0,                              //userdata1
                                        0);                             //userdata2

            // Callout firmware
            addCalloutToErrl(l_errlHndl,
                             ERRL_CALLOUT_TYPE_COMPONENT_ID,
                             ERRL_COMPONENT_ID_FIRMWARE,
                             ERRL_CALLOUT_PRIORITY_HIGH);
            break;
         }

         //Check to see if we need to make a change
         if(l_mode == OCC_MODE_NOCHANGE)
         {
             break;
         }

         // SAPPHIRE only accepts DPS-FE mode. In case OCC gets other modes, it should accept the request
         // and keep reporting back that it is in that mode. However, internally we should not
         // initiate any mode transition, i.e., OCC should remain internally in DPS-FE mode.
         if(G_sysConfigData.system_type.kvm)
         {
             G_occ_external_req_mode_kvm = l_mode;
             if (l_mode !=  OCC_MODE_DYN_POWER_SAVE)
             {
                 TRAC_ERR("SAPPHIRE only accepts DPS-FE mode(6) but requested mode is : %d", l_mode);
                 l_mode = OCC_MODE_DYN_POWER_SAVE;
             }
         }

         switch (l_mode)
         {
             case OCC_MODE_NOMINAL:           // FALL THROUGH
             case OCC_MODE_PWRSAVE:           // FALL THROUGH
             case OCC_MODE_DYN_POWER_SAVE:    // FALL THROUGH
             case OCC_MODE_DYN_POWER_SAVE_FP: // FALL THROUGH
             case OCC_MODE_TURBO:             // FALL THROUGH
             case OCC_MODE_STURBO:            // FALL THROUGH
             case OCC_MODE_FFO:               // FALL THROUGH
                 // Notify AMEC of mode change

                 // Change Mode via Transition Function
                 do
                 {
                     // Loop through mode transition table, and find the state
                     // transition function that matches the transition we need to do.
                     for(jj=0; jj<G_smgr_mode_trans_count; jj++)
                     {
                         if( ((G_smgr_mode_trans[jj].old_state == G_occ_internal_mode)
                                   || (G_smgr_mode_trans[jj].old_state == OCC_MODE_ALL) )
                              && (G_smgr_mode_trans[jj].new_state == l_mode) )
                         {
                             // We found the transtion that matches, now run the function
                             // that is associated with that state transition.
                             if(NULL != G_smgr_mode_trans[jj].trans_func_ptr)
                             {
                                 // Signal that we are now in a mode transition
                                 G_mode_transition_occuring = TRUE;
                                 // Run transition function
                                 l_errlHndl = (G_smgr_mode_trans[jj].trans_func_ptr)();
                                 // Signal that we are done with the transition
                                 G_mode_transition_occuring = FALSE;
                                 break;
                             }
                         }
                     }

                     // Check if we hit the end of the table without finding a valid
                     // mode transition.  If we did, log an internal error.
                     if(G_smgr_mode_trans_count == jj)
                     {
                         TRAC_ERR("No transition (or NULL) found for the mode change\n");
                         l_errlHndl = NULL;  //TODO: Create Error
                         break;
                     }

                     // Update the power mode for all core groups that are following system mode
                     AMEC_part_update_sysmode_policy(CURRENT_MODE());
                 }
                 while(0);

                 break;
             default:
                 //unsupported mode
                 break;
         }

         if(l_errlHndl)
         {
           // Punt !!! :-)
           break;
         }

         // Load correct thermal thresholds based on the current mode
         l_errlHndl = AMEC_data_write_thrm_thresholds(CURRENT_MODE());

         // Update the CPU speed in AME?
         // Register the New Mode?
         // Update Power Policy Requirements?
         // Update CPM Calibration

     }while(0);

     // If we have a mode change failure, Mode change flag needs to be set,
     // otherwise, it needs be be cleared/unset.
     if(l_errlHndl)
     {

     }

     // Unlock critical section
     ssx_semaphore_post(&G_smgrModeChangeSem);


     return l_errlHndl;
}
Example #4
0
// Function Specification
//
// Name: reset_state_request
//
// Description: Request Reset States
//
// End Function Specification
void reset_state_request(uint8_t i_request)
{
  //TODO:  This needs to be changed so that G_reset_state operations are
  // atomic.

  switch(i_request)
  {
    case RESET_REQUESTED_DUE_TO_ERROR:
      // In case we want to just halt() if fw requests a reset, this is
      // the place to do it.  It is disabled by default, and there is no
      // code to eanble it.
      if( G_halt_on_reset_request )
      {
          TRAC_ERR("Halt()");

          // This isn't modeled very well in simics.  OCC will go into an
          // infinite loop, which eventually would crash Simics.
          HALT_WITH_FIR_SET;
      }

      // If we have TMGT comm, and we aren't already in reset, set the reset
      // state to reset to enter the reset state machine.
      if(G_reset_state < RESET_REQUESTED_DUE_TO_ERROR)
      {
        TRAC_IMP("Activating reset required state.");

        G_reset_state = RESET_REQUESTED_DUE_TO_ERROR;

        // Post the semaphore to wakeup the thread that
        // will put us into SAFE state.
        ssx_semaphore_post(&G_dcomThreadWakeupSem);

        // Set RTL Flags here too, depending how urgent it is that we stop
        // running tasks.
        rtl_set_run_mask(RTL_FLAG_RST_REQ);
      }
      break;

    case NOMINAL_REQUESTED_DUE_TO_ERROR:
      if(G_reset_state < NOMINAL_REQUESTED_DUE_TO_ERROR)
      {
        TRAC_ERR("Going to Nominal because of error");

        // May need to add counter if multiple places request nominal
        G_reset_state = NOMINAL_REQUESTED_DUE_TO_ERROR;

        //TODO:  Will need to set some flag or event here
      }
      break;

    case RESET_NOT_REQUESTED:
      if(G_reset_state == NOMINAL_REQUESTED_DUE_TO_ERROR)
      {
        TRAC_IMP("Clearing Nominal Reset State because of error");

        // May need to add counter check if multiple places request nominal
        G_reset_state = RESET_NOT_REQUESTED;

        //TODO:  Will need to clear some flag or event here
      }
      break;

    default:
      break;

  }
}
Example #5
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;
}
Example #6
0
File: dcom.c Project: ploetzma/occ
// 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])));
}
Example #7
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;
}
Example #8
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;
    }
}