// Initialize the memory task data void memory_init() { if(G_mem_monitoring_allowed) { // Check if memory task is running (default task is for NIMBUS) const task_id_t mem_task = TASK_ID_DIMM_SM; if(!rtl_task_is_runnable(mem_task)) { if (MEM_TYPE_NIMBUS == G_sysConfigData.mem_type) { // Init DIMM state manager IPC request memory_nimbus_init(); } else { // TODO CUMULUS NOT SUPPORTED YET IN PHASE1 #if 0 TRAC_INFO("memory_init: calling centaur_init()"); centaur_init(); //no rc, handles errors internally #endif TRAC_ERR("memory_init: invalid memory type 0x%02X", G_sysConfigData.mem_type); /* * @errortype * @moduleid DIMM_MID_MEMORY_INIT * @reasoncode MEMORY_INIT_FAILED * @userdata1 memory type * @userdata2 0 * @devdesc Invalid memory type detected */ errlHndl_t err = createErrl(DIMM_MID_MEMORY_INIT, MEMORY_INIT_FAILED, OCC_NO_EXTENDED_RC, ERRL_SEV_PREDICTIVE, NULL, DEFAULT_TRACE_SIZE, G_sysConfigData.mem_type, 0); REQUEST_RESET(err); } // check if the init resulted in a reset if(isSafeStateRequested()) { TRAC_ERR("memory_init: OCC is being reset, memory init failed (type=0x%02X)", G_sysConfigData.mem_type); } else { // Initialization was successful. Set task flags to allow memory // tasks to run and also prevent from doing initialization again. G_task_table[mem_task].flags = MEMORY_DATA_RTL_FLAGS; //G_task_table[TASK_ID_CENTAUR_CONTROL].flags = MEMORY_CONTROL_RTL_FLAGS; } } } } // end memory_init()
// Schedule a GPE request for the specified DIMM state bool schedule_dimm_req(uint8_t i_state) { bool l_scheduled = false; bool scheduleRequest = true; DIMM_DBG("dimm_sm called with state 0x%02X (tick=%d)", i_state, DIMM_TICK); if (!async_request_is_idle(&G_dimm_sm_request.request)) { INTR_TRAC_ERR("dimm_sm: request is not idle."); } else { switch(i_state) { // Init case DIMM_STATE_INIT: break; // Read DIMM temp case DIMM_STATE_WRITE_MODE: case DIMM_STATE_WRITE_ADDR: case DIMM_STATE_INITIATE_READ: case DIMM_STATE_READ_TEMP: break; // I2C reset case DIMM_STATE_RESET_MASTER: case DIMM_STATE_RESET_SLAVE_P0: case DIMM_STATE_RESET_SLAVE_P0_COMPLETE: case DIMM_STATE_RESET_SLAVE_P1: case DIMM_STATE_RESET_SLAVE_P1_COMPLETE: break; default: INTR_TRAC_ERR("dimm_sm: Invalid state (0x%02X)", i_state); errlHndl_t err = NULL; /* * @errortype * @moduleid DIMM_MID_DIMM_SM * @reasoncode DIMM_INVALID_STATE * @userdata1 DIMM state * @userdata2 0 * @devdesc Invalid DIMM I2C state requested */ err = createErrl(DIMM_MID_DIMM_SM, DIMM_INVALID_STATE, OCC_NO_EXTENDED_RC, ERRL_SEV_PREDICTIVE, NULL, DEFAULT_TRACE_SIZE, i_state, 0); // Request reset since this should never happen. REQUEST_RESET(err); scheduleRequest = false; break; } if (scheduleRequest) { // Clear errors and init common arguments for GPE G_dimm_sm_args.error.error = 0; G_dimm_sm_args.state = i_state; DIMM_DBG("dimm_sm: Scheduling GPE1 DIMM I2C state 0x%02X (tick %d)", i_state, DIMM_TICK); int l_rc = gpe_request_schedule(&G_dimm_sm_request); if (0 == l_rc) { l_scheduled = true; } else { errlHndl_t l_err = NULL; INTR_TRAC_ERR("dimm_sm: schedule failed w/rc=0x%08X (%d us)", l_rc, (int) ((ssx_timebase_get())/(SSX_TIMEBASE_FREQUENCY_HZ/1000000))); /* * @errortype * @moduleid DIMM_MID_DIMM_SM * @reasoncode SSX_GENERIC_FAILURE * @userdata1 GPE shedule returned rc code * @userdata2 state * @devdesc dimm_sm schedule failed */ l_err = createErrl(DIMM_MID_DIMM_SM, SSX_GENERIC_FAILURE, ERC_DIMM_SCHEDULE_FAILURE, ERRL_SEV_PREDICTIVE, NULL, DEFAULT_TRACE_SIZE, l_rc, i_state); // Request reset since this should never happen. REQUEST_RESET(l_err); } } } return l_scheduled; } // end schedule_dimm_req()
// Verifies that each core is at the correct frequency after they have had // time to stabilize void amec_verify_pstate() { uint8_t l_core = 0; int8_t l_pstate_from_fmax = 0; gpe_bulk_core_data_t * l_core_data_ptr; pmc_pmsr_ffcdc_data_t l_pmc_pmsr_ffdc; errlHndl_t l_err = NULL; if ( (G_time_until_freq_check == 0) && ( CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE ) && ( CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE_FP ) && (!G_sysConfigData.system_type.kvm)) { // Reset the counter G_time_until_freq_check = FREQ_CHG_CHECK_TIME; // Convert fmax to the corresponding pstate l_pstate_from_fmax = proc_freq2pstate(g_amec->sys.fmax); for( l_core = 0; l_core < MAX_NUM_CORES; l_core++ ) { // If the core isn't present, skip it if(!CORE_PRESENT(l_core)) { l_pmc_pmsr_ffdc.pmsr_ffdc_data.data[l_core].value = 0; continue; } // Get pointer to core data l_core_data_ptr = proc_get_bulk_core_data_ptr(l_core); // Get the core's pmsr data l_pmc_pmsr_ffdc.pmsr_ffdc_data.data[l_core] = l_core_data_ptr->pcb_slave.pmsr; // Verify that the core is running at the correct frequency // If not, log an error if( (l_pstate_from_fmax != l_pmc_pmsr_ffdc.pmsr_ffdc_data.data[l_core].fields.local_pstate_actual) && (l_pstate_from_fmax > l_pmc_pmsr_ffdc.pmsr_ffdc_data.data[l_core].fields.pv_min) && (l_err == NULL) ) { TRAC_ERR("Frequency mismatch in core %d: actual_ps[%d] req_ps[%d] fmax[%d] mode[%d].", l_core, l_pmc_pmsr_ffdc.pmsr_ffdc_data.data[l_core].fields.local_pstate_actual, l_pstate_from_fmax, g_amec->sys.fmax, CURRENT_MODE()); fill_pmc_ffdc_buffer(&l_pmc_pmsr_ffdc.pmc_ffcdc_data); /* @ * @moduleid AMEC_VERIFY_FREQ_MID * @reasonCode TARGET_FREQ_FAILURE * @severity ERRL_SEV_PREDICTIVE * @userdata1 0 * @userdata2 0 * @userdata4 OCC_NO_EXTENDED_RC * @devdesc A core is not running at the expected frequency */ l_err = createErrl( AMEC_VERIFY_FREQ_MID, // i_modId, TARGET_FREQ_FAILURE, // i_reasonCode, OCC_NO_EXTENDED_RC, ERRL_SEV_UNRECOVERABLE, NULL, // i_trace, DEFAULT_TRACE_SIZE, // i_traceSz, 0, // i_userData1, 0); // i_userData2 //Add firmware callout addCalloutToErrl(l_err, ERRL_CALLOUT_TYPE_COMPONENT_ID, ERRL_COMPONENT_ID_FIRMWARE, ERRL_CALLOUT_PRIORITY_HIGH); //Add processor callout addCalloutToErrl(l_err, ERRL_CALLOUT_TYPE_HUID, G_sysConfigData.proc_huid, ERRL_CALLOUT_PRIORITY_MED); } } if( l_err != NULL) { //Add our register dump to the error log addUsrDtlsToErrl(l_err, (uint8_t*) &l_pmc_pmsr_ffdc, sizeof(l_pmc_pmsr_ffdc), ERRL_USR_DTL_STRUCT_VERSION_1, ERRL_USR_DTL_BINARY_DATA); REQUEST_RESET(l_err); } } }
// Check and update lock ownership for the specified i2c engine. // Returns true if OCC owns the lock, or false if host owns lock // // If host has requesed the i2c lock, it will be released and an external interrupt // will be generated/queued and function will return false. // If the host has not released the lock, function will return false. // If the host cleared its lock bit, OCC will take back ownership and return true. // bool check_and_update_i2c_lock(const uint8_t i_engine) { bool occ_owns_lock = true; if ((PIB_I2C_ENGINE_E == i_engine) || (PIB_I2C_ENGINE_D == i_engine) || (PIB_I2C_ENGINE_C == i_engine)) { bool needRetry = false; do { ocb_occflg_t original_occflags; original_occflags.value = in32(OCB_OCCFLG); LOCK_DBG("check_and_update_i2c_lock: I2C engine %d - host=%d, occ=%d (dimmTick=%d)", i_engine, original_occflags.fields.i2c_engine3_lock_host, original_occflags.fields.i2c_engine3_lock_occ, DIMM_TICK); if (occ_owns_i2c_lock(original_occflags, i_engine)) { if (host_wants_i2c_lock(original_occflags, i_engine)) { // Host requested lock, clear the OCC lock and notify host update_i2c_lock(LOCK_RELEASE, i_engine); occ_owns_lock = false; } // else OCC already owns the lock } else { // OCC does not own the lock occ_owns_lock = false; if (false == host_wants_i2c_lock(original_occflags, i_engine)) { // Host is not requesting the lock, acquire lock for OCC update_i2c_lock(LOCK_ACQUIRE, i_engine); occ_owns_lock = true; } // else Host still holds the lock } if ((occ_owns_lock) && (original_occflags.fields.i2c_engine1_lock_host == 0) && (original_occflags.fields.i2c_engine1_lock_occ == 0)) { // If neither lock bit is set, we must read back the register to make // sure the host did not set at same time (lock conflict) ocb_occflg_t verify_occflags; verify_occflags.value = in32(OCB_OCCFLG); if (host_wants_i2c_lock(verify_occflags, i_engine)) { // Host wrote their lock bit at same time, clear OCC lock and notify host update_i2c_lock(LOCK_RELEASE, i_engine); occ_owns_lock = false; } else { if (false == occ_owns_i2c_lock(verify_occflags, i_engine)) { // ERROR - OCC OWNERSHIP BIT DID NOT GET SET INTR_TRAC_ERR("check_and_update_i2c_lock: I2C lock bit did not get set (OCCFLAGS reg: 0x%08X)", verify_occflags.value); if (needRetry) { // After one retry, log error and goto safe /* * @errortype * @moduleid I2C_LOCK_UPDATE * @reasoncode OCI_WRITE_FAILURE * @userdata1 I2C engine number * @userdata2 OCC Flags register * @devdesc OCI write failure setting I2C ownership bit */ errlHndl_t err = createErrl(I2C_LOCK_UPDATE, OCI_WRITE_FAILURE, OCC_NO_EXTENDED_RC, ERRL_SEV_PREDICTIVE, NULL, DEFAULT_TRACE_SIZE, i_engine, verify_occflags.value); //Callout firmware addCalloutToErrl(err, ERRL_CALLOUT_TYPE_COMPONENT_ID, ERRL_COMPONENT_ID_FIRMWARE, ERRL_CALLOUT_PRIORITY_MED); //Callout processor addCalloutToErrl(err, ERRL_CALLOUT_TYPE_HUID, G_sysConfigData.proc_huid, ERRL_CALLOUT_PRIORITY_LOW); REQUEST_RESET(err); occ_owns_lock = false; break; } needRetry = true; } // else verify succeeded (OCC owns lock) } } } while (needRetry); } else { // Invalid engine INTR_TRAC_ERR("check_and_update_i2c_lock: Invalid engine specified: 0x%02X", i_engine); } return occ_owns_lock; } // end check_and_update_i2c_lock()
//************************************************************************* // Functions //************************************************************************* void amec_vectorize_core_sensor(sensor_t * l_sensor, vectorSensor_t * l_vector, const VECTOR_SENSOR_OP l_op, uint16_t l_sensor_elem_array_gsid) { #define VECTOR_CREATE_FAILURE 1 #define VECTOR_ADD_ELEM_FAILURE 2 int l_idx = 0; // Used to index the for loops for vector create int l_rc = 0; // Indicates failure to add a sensor to vector uint16_t l_gsid = 0xFFFF; errlHndl_t l_err = NULL; do { // Grab GSID for errl in case of failure l_gsid = l_sensor->gsid; // Vectorize the sensor sensor_vectorize(l_sensor, l_vector, l_op); // If vectorize worked, add elements to the vector sensor if(NULL != l_sensor->vector) { // Loop through cores for(l_idx = 0; l_idx < MAX_NUM_CORES; l_idx++) { // Add elements to the vector sensor sensor_vector_elem_add(l_sensor->vector, l_idx, AMECSENSOR_ARRAY_PTR(l_sensor_elem_array_gsid, l_idx)); // If core is not present, disable this vector element if(!CORE_PRESENT(l_idx)) { sensor_vector_elem_enable(l_sensor->vector, l_idx, 0 /* Disable */); } } // Sanity check, we should have MAX_NUM_CORES entries in // vector sensor if(l_sensor->vector->size != MAX_NUM_CORES) { // Set l_rc and break out so that we can create an errl l_rc = VECTOR_ADD_ELEM_FAILURE; break; } } else { // Set l_rc and break out so that we can create an errl l_rc = VECTOR_CREATE_FAILURE; break; } }while(0); if(l_rc) { //If fail to create pore flex object then there is a problem. TRAC_ERR("Failed to vectorize sensor[0x%x, 0x%x]", l_gsid, l_rc ); /* @ * @errortype * @moduleid AMEC_VECTORIZE_FW_SENSORS * @reasoncode SSX_GENERIC_FAILURE * @userdata1 return code * @userdata2 gsid of failed sensor * @userdata4 OCC_NO_EXTENDED_RC * @devdesc Firmware failure in call to vectorize sensor */ l_err = createErrl( AMEC_VECTORIZE_FW_SENSORS, //modId SSX_GENERIC_FAILURE, //reasoncode OCC_NO_EXTENDED_RC, //Extended reason code ERRL_SEV_UNRECOVERABLE, //Severity NULL,//TODO: create trace //Trace Buf DEFAULT_TRACE_SIZE, //Trace Size l_rc, //userdata1 l_gsid //userdata2 ); REQUEST_RESET(l_err); } }
// Function Specification // // Name: dbug_err_inject // // Description: Injects an error // // End Function Specification void dbug_err_inject(const cmdh_fsp_cmd_t * i_cmd_ptr, cmdh_fsp_rsp_t * i_rsp_ptr) { errlHndl_t l_err; cmdh_dbug_inject_errl_query_t *l_cmd_ptr = (cmdh_dbug_inject_errl_query_t*) i_cmd_ptr; i_rsp_ptr->data_length[0] = 0; i_rsp_ptr->data_length[1] = 0; G_rsp_status = ERRL_RC_SUCCESS; if(!strncmp(l_cmd_ptr->comp, "RST", OCC_TRACE_NAME_SIZE)) { l_err = createErrl(CMDH_DBUG_MID, //modId INTERNAL_FAILURE, //reasoncode OCC_NO_EXTENDED_RC, //Extended reason code ERRL_SEV_PREDICTIVE, //Severity NULL, //Trace Buf DEFAULT_TRACE_SIZE, //Trace Size 0xff, //userdata1 0); //userdata2 if (INVALID_ERR_HNDL == l_err) { G_rsp_status = ERRL_RC_INTERNAL_FAIL; } addCalloutToErrl(l_err, ERRL_CALLOUT_TYPE_HUID, //callout type (HUID/CompID) G_sysConfigData.proc_huid, //callout data ERRL_CALLOUT_PRIORITY_HIGH); //priority REQUEST_RESET(l_err); } else { l_err = createErrl(CMDH_DBUG_MID, //modId INTERNAL_FAILURE, //reasoncode OCC_NO_EXTENDED_RC, //Extended reason code ERRL_SEV_UNRECOVERABLE, //Severity TRAC_get_td(l_cmd_ptr->comp), //Trace Buf DEFAULT_TRACE_SIZE, //Trace Size 0xff, //userdata1 0); //userdata2 if (INVALID_ERR_HNDL == l_err) { G_rsp_status = ERRL_RC_INTERNAL_FAIL; } // Commit Error log commitErrl(&l_err); } if (G_rsp_status == ERRL_RC_INTERNAL_FAIL) { TRAC_ERR("cmdh_dbug_inject_errl: Fail creating ERR Log\n"); } else { TRAC_INFO("cmdh_dbug_inject_errl: inject errl for COMP : %s\n", l_cmd_ptr->comp); } return; }
// Function Specification // // Name: amec_slave_init // // Description: Perform initialization of any/all AMEC Slave Functions // // End Function Specification void amec_slave_init() { errlHndl_t l_err = NULL; // Error handler int rc = 0; // Return code int rc2 = 0; // Return code // Set the GPE Request Pointers to NULL in case the create fails. G_fw_timing.gpe0_timing_request = NULL; G_fw_timing.gpe1_timing_request = NULL; // Initializes the GPE routine that will be used to measure the worst case // timings for GPE0 rc = pore_flex_create( &G_gpe_nop_request[0], //gpe_req for the task &G_pore_gpe0_queue, //queue (void *) GPE_pore_nop, //entry point (uint32_t) NULL, //parm for the task SSX_WAIT_FOREVER, //no timeout (AsyncRequestCallback) amec_slv_update_gpe_sensors, //callback (void *) GPE_ENGINE_0, //callback argument ASYNC_CALLBACK_IMMEDIATE ); //options // Initializes the GPE routine that will be used to measure the worst case // timings for GPE1 rc2 = pore_flex_create( &G_gpe_nop_request[1], //gpe_req for the task &G_pore_gpe1_queue, //queue (void *)GPE_pore_nop, //entry point (uint32_t) NULL, //parm for the task SSX_WAIT_FOREVER, //no timeout (AsyncRequestCallback) amec_slv_update_gpe_sensors, //callback (void *) GPE_ENGINE_1, //callback argument ASYNC_CALLBACK_IMMEDIATE ); //options // If we couldn't create the poreFlex objects, there must be a major problem // so we will log an error and halt OCC. if( rc || rc2 ) { //If fail to create pore flex object then there is a problem. TRAC_ERR("Failed to create GPE duration poreFlex object[0x%x, 0x%x]", rc, rc2 ); /* @ * @errortype * @moduleid AMEC_INITIALIZE_FW_SENSORS * @reasoncode SSX_GENERIC_FAILURE * @userdata1 return code - gpe0 * @userdata2 return code - gpe1 * @userdata4 OCC_NO_EXTENDED_RC * @devdesc Failure to create PORE-GPE poreFlex object for FW timing * analysis. * */ l_err = createErrl( AMEC_INITIALIZE_FW_SENSORS, //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 rc, //userdata1 rc2 //userdata2 ); REQUEST_RESET(l_err); } else { // Everything was successful, so set FW timing pointers to these // GPE Request objects G_fw_timing.gpe0_timing_request = &G_gpe_nop_request[0]; G_fw_timing.gpe1_timing_request = &G_gpe_nop_request[1]; } // Initialize Vector Sensors for AMEC use amec_init_vector_sensors(); // Initialize AMEC internal parameters amec_init_gamec_struct(); }
// 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: proc_pstate_kvm_setup // // Description: Get everything set up for KVM mode // // End Function Specification void proc_pstate_kvm_setup() { int l_core; int l_rc = 0; uint32_t l_configured_cores; pcbs_pcbspm_mode_reg_t l_ppmr; pcbs_pmgp1_reg_t l_pmgp1; pcbs_power_management_bounds_reg_t l_pmbr; errlHndl_t l_errlHndl; do { //only run this in KVM mode if(!G_sysConfigData.system_type.kvm) { break; } l_configured_cores = ~in32(PMC_CORE_DECONFIGURATION_REG); // Do per-core configuration for(l_core = 0; l_core < PGP_NCORES; l_core++, l_configured_cores <<= 1) { if(!(l_configured_cores & 0x80000000)) continue; //do read-modify-write to allow pmax clip to also clip voltage (not just frequency) l_rc = getscom_ffdc(CORE_CHIPLET_ADDRESS(PCBS_PCBSPM_MODE_REG, l_core), &(l_ppmr.value), NULL); //commit errors internally if(l_rc) { TRAC_ERR("proc_pstate_kvm_setup: getscom(PCBS_PCBSPM_MODE_REG) failed. rc=%d, hw_core=%d", l_rc, l_core); break; } l_ppmr.fields.enable_clipping_of_global_pstate_req = 1; l_rc = putscom_ffdc(CORE_CHIPLET_ADDRESS(PCBS_PCBSPM_MODE_REG, l_core), l_ppmr.value, NULL); //commit errors internally if(l_rc) { TRAC_ERR("proc_pstate_kvm_setup: putscom(PCBS_PCBSPM_MODE_REG) failed. rc=%d, hw_core=%d", l_rc, l_core); break; } //per Vaidy Srinivasan, clear bit 11 in the Power Management GP1 register l_pmgp1.value = 0; l_pmgp1.fields.pm_spr_override_en = 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("proc_pstate_kvm_setup: putscom(PCBS_PMGB1_REG_OR) failed. rc=0x%08x, hw_core=%d", l_rc, l_core); break; } //set pmax/pmin clip initial settings l_pmbr.value = 0; l_pmbr.fields.pmin_clip = gpst_pmin(&G_global_pstate_table)+1; //Per David Du, we must use pmin+1 to avoid gpsa hang l_pmbr.fields.pmax_clip = gpst_pmax(&G_global_pstate_table); l_rc = putscom_ffdc(CORE_CHIPLET_ADDRESS(PCBS_POWER_MANAGEMENT_BOUNDS_REG, l_core), l_pmbr.value, NULL); //commit errors internally if(l_rc) { TRAC_ERR("proc_pstate_kvm_setup: putscom(PCBS_POWER_MANAGEMENT_BOUNDS_REG) failed. rc=0x%08x, hw_core=%d", l_rc, l_core); break; } }// end of per-core config if(l_rc) { break; } // Set the voltage clipping register to match the pmax/pmin clip values set above. pmc_rail_bounds_register_t prbr; prbr.value = in32(PMC_RAIL_BOUNDS_REGISTER); prbr.fields.pmin_rail = gpst_pmin(&G_global_pstate_table); prbr.fields.pmax_rail = gpst_pmax(&G_global_pstate_table); TRAC_IMP("pmin clip pstate = %d, pmax clip pstate = %d", prbr.fields.pmin_rail, prbr.fields.pmax_rail); out32(PMC_RAIL_BOUNDS_REGISTER, prbr.value); // Initialize the sapphire table in SRAM (sets valid bit) populate_pstate_to_sapphire_tbl(); // copy sram image into mainstore HOMER populate_sapphire_tbl_to_mem(); TRAC_IMP("proc_pstate_kvm_setup: RUNNING IN KVM MODE"); }while(0); if(l_rc) { // Create Error Log and request reset /* @ * @errortype * @moduleid PROC_PSTATE_KVM_SETUP_MOD * @reasoncode PROC_SCOM_ERROR * @userdata1 l_configured_cores * @userdata2 Return Code of call that failed * @userdata4 OCC_NO_EXTENDED_RC * @devdesc OCC failed to scom a core register */ l_errlHndl = createErrl( PROC_PSTATE_KVM_SETUP_MOD, //modId PROC_SCOM_ERROR, //reasoncode OCC_NO_EXTENDED_RC, //Extended reason code ERRL_SEV_PREDICTIVE, //Severity NULL, //Trace Buf DEFAULT_TRACE_SIZE, //Trace Size l_configured_cores, //userdata1 l_rc //userdata2 ); addCalloutToErrl(l_errlHndl, ERRL_CALLOUT_TYPE_HUID, G_sysConfigData.proc_huid, ERRL_CALLOUT_PRIORITY_HIGH); addCalloutToErrl(l_errlHndl, ERRL_CALLOUT_TYPE_COMPONENT_ID, ERRL_COMPONENT_ID_FIRMWARE, ERRL_CALLOUT_PRIORITY_MED); REQUEST_RESET(l_errlHndl); } }
// Function Specification // // Name: dcom_error_check // // Description: keep track of failure counts // // End Function Specification void dcom_error_check( const dcom_error_type_t i_error_type, const bool i_clear_error, const uint32_t i_orc, const uint32_t i_orc_ext) { static uint16_t L_rx_slv_outbox_fail_count = 0; uint16_t l_modId = 0; uint16_t *l_count_ptr = NULL; if ( i_error_type == SLAVE_INBOX ) { l_count_ptr = &G_dcomSlvInboxCounter.currentFailCount; l_modId = DCOM_MID_TASK_RX_SLV_INBOX; } // if the i_error_type == SLAVE_OUTBOX then set the outbox count else { l_count_ptr = &L_rx_slv_outbox_fail_count; l_modId = DCOM_MID_TASK_RX_SLV_OUTBOX; } if ( i_clear_error ) { *l_count_ptr = 0; } else { (*l_count_ptr)++; if ( *l_count_ptr == DCOM_250us_GAP ) { // Trace an imp trace log TRAC_IMP("l_count_ptr[%d], L_outbox[%d], L_inbox[%d]", *l_count_ptr, L_rx_slv_outbox_fail_count, G_dcomSlvInboxCounter.currentFailCount ); } else if ( *l_count_ptr == DCOM_4MS_GAP ) { // Create and commit error log // NOTE: SRC tags are NOT needed here, they are // taken care of by the caller errlHndl_t l_errl = createErrl( l_modId, //ModId i_orc, //Reasoncode i_orc_ext, //Extended reasoncode ERRL_SEV_UNRECOVERABLE, //Severity NULL, //Trace Buf DEFAULT_TRACE_SIZE, //Trace Size *l_count_ptr, //Userdata1 0 //Userdata2 ); // Commit log commitErrl( &l_errl ); // Call request nominal macro to change state REQUEST_NOMINAL(); } else if ( *l_count_ptr == DCOM_1S_GAP ) { // Create and commit error log // NOTE: SRC tags are NOT needed here, they are // taken care of by the caller errlHndl_t l_errl = createErrl( l_modId, //ModId i_orc, //Reasoncode i_orc_ext, //Extended reasoncode ERRL_SEV_UNRECOVERABLE, //Severity NULL, //Trace Buf DEFAULT_TRACE_SIZE, //Trace Size *l_count_ptr, //Userdata1 0 //Userdata2 ); // Commit log // Call request reset macro REQUEST_RESET(l_errl); } } }
// Function Specification // // Name: dcom_initialize_pbax_queues // // Description: Initialize the PBAX Queues for sending doorbells // // End Function Specification void dcom_initialize_pbax_queues(void) { // SSX return codes int l_rc = 0; do { //disabled pbax send before configuring PBAX pbax_send_disable(); // TODO: With the new design, PBAX node and chip IDs are set by hostboot // Remove these ID parameters from the pbax_configure function? l_rc = pbax_configure(G_occ_role, // master G_pbax_id.node_id, // node id G_pbax_id.chip_id, // chipd id PBAX_CONFIGURE_RCV_GROUP_MASK); // group_mask if(l_rc != 0) { TRAC_ERR("Error configuring the pbax rc[%x]",l_rc); break; } //enabled pbax send does not return errors pbax_send_enable(); if(G_occ_role == OCC_SLAVE) { // create pbax rx queue 1 l_rc = pbax_queue_create( &G_pbax_read_queue[1], //queue ASYNC_ENGINE_PBAX_PUSH1, //engine G_pbax_queue_rx1_buffer, //cq base NUM_ENTRIES_PBAX_QUEUE1, //cq entries PBAX_INTERRUPT_PROTOCOL_AGGRESSIVE //protocol ); if(l_rc != 0) { TRAC_ERR("Error creating pbax queue 1 rc[%x]",l_rc); break; } // create pbax rx queue o l_rc = pbax_queue_create( &G_pbax_read_queue[0],//queue ASYNC_ENGINE_PBAX_PUSH0, //engine G_pbax_queue_rx0_buffer, //cq base NUM_ENTRIES_PBAX_QUEUE0, //cq entries PBAX_INTERRUPT_PROTOCOL_AGGRESSIVE //protocol ); if(l_rc != 0) { TRAC_ERR("Error creating pbax queue 0 rc[%x]",l_rc); break; } // enable the read 1 queue l_rc = pbax_queue_enable(&G_pbax_read_queue[1]); if(l_rc != 0) { TRAC_ERR("Error enabling queue 1 rc[%x]",l_rc); break; } } if(G_occ_role == OCC_MASTER) { l_rc = pbax_target_create( &G_pbax_multicast_target, // target, PBAX_BROADCAST, // type PBAX_SYSTEM, // scope TODO 0, // queue G_pbax_id.node_id, // node PBAX_BROADCAST_GROUP); // chip_or_group if(l_rc != 0) { TRAC_ERR("Error creating pbax target for master TX operations SSXrc[%x]",l_rc); break; } } }while(0); if(l_rc) { /* @ * @errortype * @moduleid DCOM_MID_INIT_PBAX_QUEUES * @reasoncode SSX_GENERIC_FAILURE * @userdata1 SSX RC * @userdata4 OCC_NO_EXTENDED_RC * @devdesc Failure initializing the PBAX queues */ errlHndl_t l_errl = createErrl( DCOM_MID_INIT_PBAX_QUEUES, //ModId SSX_GENERIC_FAILURE, //Reasoncode OCC_NO_EXTENDED_RC, //Extended reasoncode ERRL_SEV_UNRECOVERABLE, //Severity NULL, //Trace Buf DEFAULT_TRACE_SIZE, //Trace Size l_rc, //Userdata1 0 //Userdata2 ); // Commit log and request reset REQUEST_RESET(l_errl); } }