// 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; }
// 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"); }
// 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]))); }
//************************************************************************* // 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; }
// 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; }
// 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; }
// 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; } }
// 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 }
// 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; }
// 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; }
// 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); } }
// 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; }
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); }