// Function Specification // // Name: cmdh_mnfg_run_stop_slew // // Description: This function handles the manufacturing command to start // or stop frequency autoslewing. // // End Function Specification uint8_t cmdh_mnfg_run_stop_slew(const cmdh_fsp_cmd_t * i_cmd_ptr, cmdh_fsp_rsp_t * o_rsp_ptr) { uint8_t l_rc = ERRL_RC_SUCCESS; uint16_t l_fmin = 0; uint16_t l_fmax = 0; uint16_t l_step_size = 0; uint16_t l_step_delay = 0; uint32_t l_temp = 0; mnfg_run_stop_slew_cmd_t *l_cmd_ptr = (mnfg_run_stop_slew_cmd_t*) i_cmd_ptr; mnfg_run_stop_slew_rsp_t *l_rsp_ptr = (mnfg_run_stop_slew_rsp_t*) o_rsp_ptr; do { // This command is only supported on Master OCC if (G_occ_role == OCC_SLAVE) { TRAC_ERR("cmdh_mnfg_run_stop_slew: Mnfg command not supported on Slave OCCs!"); break; } // Do some basic input verification if ((l_cmd_ptr->action > MNFG_INTF_SLEW_STOP) || (l_cmd_ptr->step_mode > MNFG_INTF_FULL_SLEW)) { // Invalid values were passed by the user! TRAC_ERR("cmdh_mnfg_run_stop_slew: Invalid values were detected! action[0x%02x] step_mode[0x%02x]", l_cmd_ptr->action, l_cmd_ptr->step_mode); l_rc = ERRL_RC_INVALID_DATA; break; } // Are we stopping the auto-slew function? if (l_cmd_ptr->action == MNFG_INTF_SLEW_STOP) { // Collect the slew count l_rsp_ptr->slew_count = AMEC_MST_CUR_SLEW_COUNT(); // Collect the frequency range used for the auto-slew l_rsp_ptr->fstart = AMEC_MST_CUR_MNFG_FMIN(); l_rsp_ptr->fstop = AMEC_MST_CUR_MNFG_FMAX(); TRAC_INFO("cmdh_mnfg_run_stop_slew: Auto-slewing has been stopped. Count[%u] fstart[%u] fstop[%u]", AMEC_MST_CUR_SLEW_COUNT(), AMEC_MST_CUR_MNFG_FMIN(), AMEC_MST_CUR_MNFG_FMAX()); // Send a signal to RTL to stop auto-slewing AMEC_MST_STOP_AUTO_SLEW(); // We are done break; } // If we made it here, that means we are starting up a slew run // First, determine the Fmax and Fmin for the slew run if (l_cmd_ptr->bottom_mode == OCC_MODE_PWRSAVE) { // If bottom mode is Static Power Save, use the min frequency // available l_fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY]; } else { l_fmin = G_sysConfigData.sys_mode_freq.table[l_cmd_ptr->bottom_mode]; } l_fmax = G_sysConfigData.sys_mode_freq.table[l_cmd_ptr->high_mode]; // Add the percentages to compute the min/max frequencies l_fmin = l_fmin + (l_fmin * l_cmd_ptr->bottom_percent)/100; l_fmax = l_fmax + (l_fmax * l_cmd_ptr->high_percent)/100; TRAC_INFO("cmdh_mnfg_run_stop_slew: We are about to start auto-slewing function"); TRAC_INFO("cmdh_mnfg_run_stop_slew: bottom_mode[0x%.2X] freq[%u] high_mode[0x%.2X] freq[%u]", l_cmd_ptr->bottom_mode, l_fmin, l_cmd_ptr->high_mode, l_fmax); // Determine the frequency step size and the step delay if (l_cmd_ptr->step_mode == MNFG_INTF_FULL_SLEW) { l_step_size = l_fmax - l_fmin; // Disable step delays if full slew mode has been selected l_step_delay = 0; TRAC_INFO("cmdh_mnfg_run_stop_slew: Enabling full-slew mode with step_size[%u] step_delay[%u]", l_step_size, l_step_delay); } else { l_step_size = (uint16_t)G_mhz_per_pstate; // Translate the step delay to internal OCC ticks l_temp = (l_cmd_ptr->step_delay * 1000) / AMEC_US_PER_TICK; l_step_delay = (uint16_t) l_temp; TRAC_INFO("cmdh_mnfg_run_stop_slew: Enabling single-step mode with step_size[%u] step_delay[%u]", l_step_size, l_step_delay); } // Now, load the values for RTL consumption AMEC_MST_SET_MNFG_FMIN(l_fmin); AMEC_MST_SET_MNFG_FMAX(l_fmax); AMEC_MST_SET_MNFG_FSTEP(l_step_size); AMEC_MST_SET_MNFG_DELAY(l_step_delay); // Reset the slew-counter before we start auto-slewing AMEC_MST_CUR_SLEW_COUNT() = 0; // Wait a little bit for RTL to process above parameters ssx_sleep(SSX_MILLISECONDS(5)); // Send a signal to RTL to start auto-slewing AMEC_MST_START_AUTO_SLEW(); // We are auto-slewing now, populate the response packet l_rsp_ptr->slew_count = 0; l_rsp_ptr->fstart = l_fmin; l_rsp_ptr->fstop = l_fmax; }while(0); // Populate the response data packet G_rsp_status = l_rc; l_rsp_ptr->data_length[0] = 0; l_rsp_ptr->data_length[1] = MNFG_INTF_RUN_STOP_SLEW_RSP_SIZE; return l_rc; }
// Function Specification // // Name: Dcom_thread_routine // // Description: Purpose of this task is to handle messages passed from // Master to Slave and vice versa. // // Nothing in this thread should be time-critical, but should // happen more often than the 1-second that other threads run // at. // // This thread currently runs ~1ms, based on the RTL loop of // 250us. // // FWIW -- It is pointless to set this thread to run any more // often than the length of the RTL loop, since it is acting // on data passed back and forth via that loop. // // End Function Specification void Dcom_thread_routine(void *arg) { OCC_STATE l_newOccState = 0; OCC_MODE l_newOccMode = 0; SsxTimer l_timeout_timer; errlHndl_t l_errlHndl = NULL; // -------------------------------------------------- // Create a timer that pops every 10 seconds to wake up // this thread, in case a semaphore never gets posted. // TODO: Is this really needed? // -------------------------------------------------- ssx_timer_create(&l_timeout_timer, (SsxTimerCallback) ssx_semaphore_post, (void *) &G_dcomThreadWakeupSem); ssx_timer_schedule(&l_timeout_timer, SSX_SECONDS(10), SSX_SECONDS(10)); for(;;) { // -------------------------------------------------- // Wait on Semaphore until we get new data over DCOM // (signalled by sem_post() or timeout occurs. // Sem timeout is designed to be the slowest // interval we will attempt to run this thread at. // -------------------------------------------------- // Wait for sem_post before we run through this thread. ssx_semaphore_pend(&G_dcomThreadWakeupSem, SSX_WAIT_FOREVER); // -------------------------------------------------- // Counter to ensure thread is running (can wrap) // -------------------------------------------------- G_dcom_thread_counter++; // -------------------------------------------------- // Check if we need to update the sapphire table // -------------------------------------------------- if(G_sysConfigData.system_type.kvm) { proc_check_for_sapphire_updates(); } // -------------------------------------------------- // Set Mode and State Based on Master // -------------------------------------------------- l_newOccState = (G_occ_master_state == CURRENT_STATE()) ? OCC_STATE_NOCHANGE : G_occ_master_state; if(G_sysConfigData.system_type.kvm) { l_newOccMode = (G_occ_master_mode == G_occ_external_req_mode_kvm ) ? OCC_MODE_NOCHANGE : G_occ_master_mode; } else { l_newOccMode = (G_occ_master_mode == CURRENT_MODE() ) ? OCC_MODE_NOCHANGE : G_occ_master_mode; } // Override State if SAFE state is requested l_newOccState = ( isSafeStateRequested() ) ? OCC_STATE_SAFE : l_newOccState; // Override State if we are in SAFE state already l_newOccState = ( OCC_STATE_SAFE == CURRENT_STATE() ) ? OCC_STATE_NOCHANGE : l_newOccState; if( (OCC_STATE_NOCHANGE != l_newOccState) || (OCC_MODE_NOCHANGE != l_newOccMode) ) { // If we're active, then we should always process the mode change first // If we're not active, then we should always process the state change first if(OCC_STATE_ACTIVE == CURRENT_STATE()) { // Set the new mode l_errlHndl = SMGR_set_mode(l_newOccMode, 0 /* TODO V/F */ ); if(l_errlHndl) { commitErrl(&l_errlHndl); } // Set the new state l_errlHndl = SMGR_set_state(l_newOccState); if(l_errlHndl) { commitErrl(&l_errlHndl); } } else { // Set the new state l_errlHndl = SMGR_set_state(l_newOccState); if(l_errlHndl) { commitErrl(&l_errlHndl); } // Set the new mode l_errlHndl = SMGR_set_mode(l_newOccMode, 0 /* TODO V/F */ ); if(l_errlHndl) { commitErrl(&l_errlHndl); } } } // -------------------------------------------------- // DCM PStates // \_ can do sem_post to increment through state machine // -------------------------------------------------- if(OCC_STATE_SAFE != CURRENT_STATE()) { proc_gpsm_dcm_sync_enable_pstates_smh(); } // -------------------------------------------------- // SSX Sleep // -------------------------------------------------- // Even if semaphores are continually posted, there is no reason // for us to run this thread any more often than once every 250us // so we don't starve any other thread ssx_sleep(SSX_MICROSECONDS(250)); } }