/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/occ_405/state.c $ */ /* */ /* OpenPOWER OnChipController Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2011,2016 */ /* [+] International Business Machines Corp. */ /* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ /* You may obtain a copy of the License at */ /* */ /* http://www.apache.org/licenses/LICENSE-2.0 */ /* */ /* Unless required by applicable law or agreed to in writing, software */ /* distributed under the License is distributed on an "AS IS" BASIS, */ /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ /* implied. See the License for the specific language governing */ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ #include #include #include #include "ssx_io.h" #include "trac.h" #include "rtls.h" #include "state.h" #include "dcom.h" #include "occ_service_codes.h" #include "proc_pstate.h" #include "cmdh_fsp_cmds_datacnfg.h" #include "cmdh_fsp.h" #include "proc_data.h" // TEMP -- Doesn't exist anymore //#include "heartbeat.h" #include "scom.h" #include #include extern bool G_mem_monitoring_allowed; extern task_t G_task_table[TASK_END]; // Global task table // Maximum allowed value approx. 16.3 ms #define PCBS_HEARBEAT_TIME_US 16320 errlHndl_t SMGR_standby_to_observation(); errlHndl_t SMGR_standby_to_active(); errlHndl_t SMGR_observation_to_standby(); errlHndl_t SMGR_observation_to_active(); errlHndl_t SMGR_active_to_observation(); errlHndl_t SMGR_active_to_standby(); errlHndl_t SMGR_all_to_safe(); // State that OCC is currently in OCC_STATE G_occ_internal_state = OCC_STATE_STANDBY; // State that OCC is requesting that TMGT put OCC into OCC_STATE G_occ_internal_req_state = OCC_STATE_NOCHANGE; // State that TMGT wants to put OCC into OCC_STATE G_occ_external_req_state = OCC_STATE_NOCHANGE; // Indicates if we are currently in a state transition bool G_state_transition_occuring = FALSE; // State that OCC Master is requesting OCC_STATE G_occ_master_state = OCC_STATE_NOCHANGE; // Semaphore to allow state change to be called from multiple threads SsxSemaphore G_smgrStateChangeSem; // Table that indicates which functions should be run for a given mode // transition. const smgr_state_trans_t G_smgr_state_trans[] = { /* ----- SPECIFIC CASE STATE TRANSITIONS ----- */ /* These are specific state transitions for when it matters what * state we were in before the transition. These must come before * the agnostic state transitions below, and will be run instead of * those catch-all transition functions. */ /* Current State New State Transition Function */ {OCC_STATE_STANDBY, OCC_STATE_OBSERVATION, &SMGR_standby_to_observation}, {OCC_STATE_STANDBY, OCC_STATE_ACTIVE, &SMGR_standby_to_active}, {OCC_STATE_OBSERVATION, OCC_STATE_STANDBY, &SMGR_observation_to_standby}, {OCC_STATE_OBSERVATION, OCC_STATE_ACTIVE, &SMGR_observation_to_active}, {OCC_STATE_ACTIVE, OCC_STATE_OBSERVATION, &SMGR_active_to_observation}, {OCC_STATE_ACTIVE, OCC_STATE_STANDBY, &SMGR_active_to_standby}, /* ----- DEFAULT STATE TRANSITIONS ----- */ /* These are default state transitions for when it doesn't matter what * state we were in before the transition. */ /* Current State New State Transition Function */ {OCC_STATE_ALL, OCC_STATE_SAFE, &SMGR_all_to_safe}, }; const uint8_t G_smgr_state_trans_count = sizeof(G_smgr_state_trans)/sizeof(smgr_state_trans_t); uint32_t G_smgr_validate_data_active_mask = SMGR_VALIDATE_DATA_ACTIVE_MASK_HARDCODES; uint32_t G_smgr_validate_data_observation_mask = SMGR_VALIDATE_DATA_OBSERVATION_MASK_HARDCODES; // Function Specification // // Name: SMGR_is_mode_transitioning // // Description: // // End Function Specification inline bool SMGR_is_state_transitioning(void) { return G_state_transition_occuring; } // Function Specification // // Name: // // Description: // // End Function Specification errlHndl_t SMGR_standby_to_observation() { errlHndl_t l_errlHndl = NULL; static bool l_error_logged = FALSE; // To prevent trace and error log happened over and over if( SMGR_MASK_OBSERVATION_READY == (SMGR_validate_get_valid_states() & SMGR_MASK_OBSERVATION_READY)) { l_error_logged = FALSE; TRAC_IMP("SMGR: Standby to Observation Transition Started"); memory_init(); // Set the RTL Flags to indicate which tasks can run // - Set OBSERVATION b/c we're in OBSERVATION State rtl_clr_run_mask_deferred(RTL_FLAG_STANDBY); rtl_set_run_mask_deferred(RTL_FLAG_OBS); // Initialize key freq2pstate Global parameters proc_pstate_initialize(); // Set the actual STATE now that we have finished everything else CURRENT_STATE() = OCC_STATE_OBSERVATION; TRAC_IMP("SMGR: Standby to Observation Transition Completed"); } else if(FALSE == l_error_logged) { l_error_logged = TRUE; TRAC_ERR("SMGR: Standby to Observation Transition Failed"); /* @ * @errortype * @moduleid MAIN_STATE_TRANSITION_MID * @reasoncode INTERNAL_FAILURE * @userdata1 none * @userdata4 ERC_STATE_FROM_STB_TO_OBS_FAILURE * @devdesc Failed changing from standby to observation */ l_errlHndl = createErrl(MAIN_STATE_TRANSITION_MID, //modId INTERNAL_FAILURE, //reasoncode ERC_STATE_FROM_STB_TO_OBS_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); } return l_errlHndl; } // Function Specification // // Name: // // Description: // // End Function Specification errlHndl_t SMGR_observation_to_standby() { errlHndl_t l_errlHndl = NULL; TRAC_IMP("SMGR: Observation to Standby Transition Started"); // Set the RTL Flags to indicate which tasks can run // - Clear ACTIVE b/c not in ACTIVE State // - Clear OBSERVATION b/c not in OBSERVATION State rtl_clr_run_mask_deferred(RTL_FLAG_ACTIVE | RTL_FLAG_OBS ); rtl_set_run_mask_deferred(RTL_FLAG_STANDBY); // Set the actual STATE now that we have finished everything else CURRENT_STATE() = OCC_STATE_STANDBY; TRAC_IMP("SMGR: Observation to Standby Transition Completed"); return l_errlHndl; } // Function Specification // // Name: // // Description: // // End Function Specification errlHndl_t SMGR_observation_to_active() { errlHndl_t l_errlHndl = NULL; /* TEMP -- UNNECCESSARY IN PHASE1 */ #if 0 static bool l_error_logged = FALSE; // To prevent trace and error log happened over and over int l_extRc = OCC_NO_EXTENDED_RC; int l_rc = 0; // Pstates are enabled via an IPC call to PGPE once the OCC reaches the // observation state. We still have to check that the enable_pstates() IPC job // on the PGPE has completed before transitioned to the active state. otherwise, // wait TBD seconds in case we are going directly from Standby to Active // (pstate init only happens in observation state, so it might not be // done yet...must call it in this while loop since it is done in this // same thread...) // // NOTE that this is really unnecessary if you follow the TMGT OCC // Interface Spec, which tells you that you need to check for the "Active // Ready" bit in the poll response before you go to active state. // But since we have scenerios where TMGT isn't the one putting us in // active state (we are going there automatically) we needed to add this // If we have all data we need to go to active state, but don't have pstates // enabled yet...then we will do the aforementioned wait if(((DATA_get_present_cnfgdata() & SMGR_VALIDATE_DATA_ACTIVE_MASK) == SMGR_VALIDATE_DATA_ACTIVE_MASK)) { SsxTimebase start = ssx_timebase_get(); while( ! proc_is_hwpstate_enabled() ) { SsxInterval timeout = SSX_SECONDS(5); if ((ssx_timebase_get() - start) > timeout) { if(FALSE == l_error_logged) { TRAC_ERR("SMGR: Timeout waiting for Pstates to be enabled, pmc_mode[%08x], chips_present[%02x], pmc_deconfig[%08x]", in32(PMC_MODE_REG), G_sysConfigData.is_occ_present, in32(PMC_CORE_DECONFIGURATION_REG)); } l_extRc = ERC_GENERIC_TIMEOUT; break; } ssx_sleep(SSX_MICROSECONDS(500)); } if(proc_is_hwpstate_enabled() && G_sysConfigData.system_type.kvm) { TRAC_IMP("SMGR: Pstates are enabled, continuing with state trans"); } } // Check if all conditions are met to transition to active state. If // they aren't, then log an error and fail to change state. if( (SMGR_MASK_ACTIVE_READY == (SMGR_validate_get_valid_states() & SMGR_MASK_ACTIVE_READY)) && proc_is_hwpstate_enabled() ) { l_error_logged = FALSE; TRAC_IMP("SMGR: Observation to Active Transition Started"); // Set the RTL Flags to indicate which tasks can run // - Clear OBSERVATION b/c not in OBSERVATION State // - Set ACTIVE b/c we're in ACTIVE State rtl_clr_run_mask_deferred(RTL_FLAG_OBS); rtl_set_run_mask_deferred(RTL_FLAG_ACTIVE); // Ensure that the dpll override (enabled when mfg biases freq) has been disabled. int l_core; uint32_t l_configured_cores; pcbs_pmgp1_reg_t l_pmgp1; l_configured_cores = ~in32(PMC_CORE_DECONFIGURATION_REG); for(l_core = 0; l_core < PGP_NCORES; l_core++, l_configured_cores <<= 1) { if(!(l_configured_cores & 0x80000000)) continue; l_pmgp1.value = 0; l_pmgp1.fields.dpll_freq_override_enable = 1; l_rc = putscom_ffdc(CORE_CHIPLET_ADDRESS(PCBS_PMGP1_REG_AND, l_core), ~l_pmgp1.value, NULL); //commit errors internally if(l_rc) { TRAC_ERR("Failed disabling dpll frequency override. rc=0x%08x, core=%d", l_rc, l_core); break; } } if(!l_rc) { // Set the actual STATE now that we have finished everything else CURRENT_STATE() = OCC_STATE_ACTIVE; TRAC_IMP("SMGR: Observation to Active Transition Completed"); // Configure and enable the PCB slave heartbeat timer // // task_core_data is running in every RTL tick and scheduling a run // of gpe_get_per_core_data which will do a getscom on // PCBS_PMSTATEHISTOCC_REG. We will use PCBS_PMSTATEHISTOCC_REG as // the PCBS heartbeat trigger register. unsigned int l_actual_pcbs_hb_time = 0; ChipConfigCores l_cfgd_cores = (ChipConfigCores)((uint64_t)core_configuration() >> 16); TRAC_IMP("Configuring PCBS heartbeat for configured cores=0x%8.8x", l_cfgd_cores); TRAC_IMP("OCC configuration view: G_present_hw_cores=0x%8.8x, G_present_cores=0x%8.8x", G_present_hw_cores, G_present_cores); // Setup the pcbs heartbeat timer l_rc = pcbs_hb_config(1, // enable = yes l_cfgd_cores, PCBS_PMSTATEHISTOCC_REG, PCBS_HEARBEAT_TIME_US, 0, // force = no &l_actual_pcbs_hb_time); if (l_rc) { TRAC_ERR("Failure configuring the PCBS heartbeat timer, rc=%d", l_rc); // FIXME #state_c_002 Add appropriate callouts for // serviceability review l_extRc = ERC_STATE_HEARTBEAT_CFG_FAILURE; } else { TRAC_IMP("PCBS heartbeat enabled, requested time(us)=%d, actual time(us)=%d", PCBS_HEARBEAT_TIME_US, l_actual_pcbs_hb_time); } // TODO: #state_c_001 Manually configuring the PMC // heartbeat until pmc_hb_config is shown to be working // Reference SW238882 for more information on updates needed in // pmc_hb_config. Note that if PMC parameter hangpulse pre-divider // is 0 then the PMC heartbeat counter uses nest_nclck/4 instead of // the hangpulse to count the heartbeat timeout. pmc_parameter_reg0_t ppr0; pmc_occ_heartbeat_reg_t pohr; pohr.value = in32(PMC_OCC_HEARTBEAT_REG); ppr0.value = in32(PMC_PARAMETER_REG0); pohr.fields.pmc_occ_heartbeat_en = 0; // This combined with the hang pulse count and pre-divider yields // about a 2 second timeout pohr.fields.pmc_occ_heartbeat_time = 0xffff; TRAC_IMP("Configure PMC heartbeat, heartbeat_time=0x%x", pohr.fields.pmc_occ_heartbeat_time); ppr0.fields.hangpulse_predivider = 1; TRAC_IMP("Configure PMC parm reg predivider=%d", ppr0.fields.hangpulse_predivider); // Write registers twice, known issue with heartbeat reg out32(PMC_OCC_HEARTBEAT_REG, pohr.value); out32(PMC_OCC_HEARTBEAT_REG, pohr.value); out32(PMC_PARAMETER_REG0, ppr0.value); out32(PMC_PARAMETER_REG0, ppr0.value); TRAC_IMP("Enable PMC heartbeat timer"); pohr.value = in32(PMC_OCC_HEARTBEAT_REG); pohr.fields.pmc_occ_heartbeat_en = 1; out32(PMC_OCC_HEARTBEAT_REG, pohr.value); out32(PMC_OCC_HEARTBEAT_REG, pohr.value); } } else { //trace and log an error. l_rc = -1; } if(l_rc) { TRAC_ERR("SMGR: Observation to Active Transition Failed, cnfgdata=0x%08x, reqd=0x%08x", DATA_get_present_cnfgdata(), SMGR_VALIDATE_DATA_ACTIVE_MASK); } if(l_rc && FALSE == l_error_logged) { l_error_logged = TRUE; /* @ * @errortype * @moduleid MAIN_STATE_TRANSITION_MID * @reasoncode INTERNAL_FAILURE * @userdata1 SMGR_MASK_ACTIVE_READY * @userdata2 valid states * @userdata4 ERC_STATE_FROM_OBS_TO_STB_FAILURE * @devdesc Failed changing from observation to standby */ l_errlHndl = createErrl(MAIN_STATE_TRANSITION_MID, //modId INTERNAL_FAILURE, //reasoncode l_extRc, //Extended reason code ERRL_SEV_UNRECOVERABLE, //Severity NULL, //Trace Buf DEFAULT_TRACE_SIZE, //Trace Size SMGR_MASK_ACTIVE_READY, //userdata1 SMGR_validate_get_valid_states());//userdata2 // Callout firmware addCalloutToErrl(l_errlHndl, ERRL_CALLOUT_TYPE_COMPONENT_ID, ERRL_COMPONENT_ID_FIRMWARE, ERRL_CALLOUT_PRIORITY_HIGH); } #endif return l_errlHndl; } // Function Specification // // Name: SMGR_active_to_observation // // Description: // // End Function Specification errlHndl_t SMGR_active_to_observation() { errlHndl_t l_errlHndl = NULL; TRAC_IMP("SMGR: Active to Observation Transition Started"); // Set the RTL Flags to indicate which tasks can run // - Set OBSERVATION b/c in OBSERVATION State // - Clear ACTIVE b/c not in ACTIVE State rtl_clr_run_mask_deferred(RTL_FLAG_ACTIVE); rtl_set_run_mask_deferred(RTL_FLAG_OBS); // Set the actual STATE now that we have finished everything else CURRENT_STATE() = OCC_STATE_OBSERVATION; TRAC_IMP("SMGR: Active to Observation Transition Completed"); return l_errlHndl; } // Function Specification // // Name: SMGR_active_to_standby // // Description: // // End Function Specification errlHndl_t SMGR_active_to_standby() { errlHndl_t l_errlHndl = NULL; TRAC_IMP("SMGR: Active to Standby Transition Started"); // Transtion through both functions on this multi-state transtion l_errlHndl = SMGR_active_to_observation(); if(NULL == l_errlHndl) { l_errlHndl = SMGR_observation_to_standby(); } if(l_errlHndl) { TRAC_ERR("SMGR: Active to Standby Transition Failed"); } else { TRAC_IMP("SMGR: Active to Standby Transition Completed"); } return l_errlHndl; } // Function Specification // // Name: SMGR_standby_to_active // // Description: Makes the appropriate calls when transitioning from // standby to active. // // End Function Specification errlHndl_t SMGR_standby_to_active() { errlHndl_t l_errlHndl = NULL; TRAC_IMP("SMGR: Standby to Active Transition Started"); // Transtion through both functions on this multi-state transtion l_errlHndl = SMGR_standby_to_observation(); if(NULL == l_errlHndl) { l_errlHndl = SMGR_observation_to_active(); } if(l_errlHndl) { TRAC_ERR("SMGR: Standby to Active Transition Failed"); } else { TRAC_IMP("SMGR: Standby to Active Transition Completed"); } return l_errlHndl; } // Function Specification // // Name: SMGR_all_to_safe // // Description: // // End Function Specification errlHndl_t SMGR_all_to_safe() { errlHndl_t l_errlHndl = NULL; TRAC_IMP("SMGR: All States to Safe Transition Started"); // If we are master, make sure we are broadcasting that the requested // state is "safe state" if (OCC_MASTER == G_occ_role) { G_occ_external_req_state = OCC_STATE_SAFE; } // If we are master, we will wait 15ms to go to full on safe mode // This is to give the slaves time to see that we are broadcasting // Safe State, and react to it. This must be > 10ms. It doesn't hurt // to do this on the slaves also. ssx_sleep(SSX_MILLISECONDS(15)); // Set the RTL Flags to indicate which tasks can run // - Clear ACTIVE b/c not in ACTIVE State // - Clear OBSERVATION b/c not in OBSERVATION State // - Clear STANDBY b/c not in STANDBY State rtl_clr_run_mask_deferred(RTL_FLAG_ACTIVE | RTL_FLAG_OBS | RTL_FLAG_STANDBY); // Only reset task & wdt task will run from now on // !!! There is no recovery to this except a reset !!! rtl_set_run_mask_deferred(RTL_FLAG_RST_REQ); // Notes: // - We can still talk to FSP // - We will still be able to go out on PIB // - We will still attempt to load an applet if told to do so // - The master will no longer broadcast to slaves, and vice versa // Set the actual STATE now that we have finished everything else CURRENT_STATE() = OCC_STATE_SAFE; TRAC_IMP("SMGR: All States to Safe Transition Completed"); return l_errlHndl; } // Function Specification // // Name: SMGR_set_state // // Description: // // End Function Specification errlHndl_t SMGR_set_state(OCC_STATE i_new_state) { errlHndl_t l_transResult = NULL; //Was the transition successful? int jj=0; do { // Get lock for critical section if(ssx_semaphore_pend(&G_smgrStateChangeSem,SSX_WAIT_FOREVER)) { /* @ * @errortype * @moduleid MAIN_STATE_TRANSITION_MID * @reasoncode SSX_GENERIC_FAILURE * @userdata1 none * @userdata4 ERC_RUNNING_SEM_PENDING_FAILURE * @devdesc SSX semaphore related failure */ l_transResult = createErrl(MAIN_STATE_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 addCalloutToErrl(l_transResult, ERRL_CALLOUT_TYPE_COMPONENT_ID, ERRL_COMPONENT_ID_FIRMWARE, ERRL_CALLOUT_PRIORITY_HIGH); break; } //If there is no change to the state, just exit if(i_new_state == OCC_STATE_NOCHANGE) { break; } // Loop through state transition table, and find the state // transition function that matches the transition we need to do. for(jj=0; jj