diff options
Diffstat (limited to 'src/occ_405/proc')
-rwxr-xr-x | src/occ_405/proc/proc_data.c | 837 | ||||
-rwxr-xr-x | src/occ_405/proc/proc_data.h | 179 | ||||
-rwxr-xr-x | src/occ_405/proc/proc_data_control.c | 264 | ||||
-rwxr-xr-x | src/occ_405/proc/proc_data_control.h | 48 | ||||
-rwxr-xr-x | src/occ_405/proc/proc_data_service_codes.h | 41 | ||||
-rwxr-xr-x | src/occ_405/proc/proc_pstate.c | 1080 | ||||
-rwxr-xr-x | src/occ_405/proc/proc_pstate.h | 131 | ||||
-rwxr-xr-x | src/occ_405/proc/test/Makefile | 89 | ||||
-rwxr-xr-x | src/occ_405/proc/test/app.mk | 104 | ||||
-rwxr-xr-x | src/occ_405/proc/test/main.c | 352 |
10 files changed, 3125 insertions, 0 deletions
diff --git a/src/occ_405/proc/proc_data.c b/src/occ_405/proc/proc_data.c new file mode 100755 index 0000000..8b0bda8 --- /dev/null +++ b/src/occ_405/proc/proc_data.c @@ -0,0 +1,837 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/proc/proc_data.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* [+] 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 "proc_data.h" +#include "pgp_async.h" +#include "threadSch.h" +#include "pmc_register_addresses.h" +#include "proc_data_service_codes.h" +#include "occ_service_codes.h" +#include "errl.h" +#include "trac.h" +#include "rtls.h" +#include "apss.h" +#include "state.h" +#include "proc_data_control.h" + +//Global array of core data buffers +GPE_BUFFER(gpe_bulk_core_data_t G_core_data[MAX_NUM_FW_CORES+NUM_CORE_DATA_DOUBLE_BUF+NUM_CORE_DATA_EMPTY_BUF]) = {{{0}}}; + +//Global array of core data pointers +gpe_bulk_core_data_t * G_core_data_ptrs[MAX_NUM_FW_CORES] = { &G_core_data[0], &G_core_data[1], + &G_core_data[2], &G_core_data[3], &G_core_data[4], &G_core_data[5], &G_core_data[6], + &G_core_data[7], &G_core_data[8], &G_core_data[9], &G_core_data[10], &G_core_data[11] }; + +//Global structures for gpe get core data parms +GPE_BUFFER(GpeGetCoreDataParms G_low_cores_data_parms); +GPE_BUFFER(GpeGetCoreDataParms G_high_cores_data_parms); + +//We will have separate bulk core data structure for low and high cores. +//Global low and high cores structures used for task data pointers. +bulk_core_data_task_t G_low_cores = { 0, 0, 5, &G_core_data[12] }; +bulk_core_data_task_t G_high_cores = { 6, 6, 11, &G_core_data[13] }; + +//AMEC needs to know when data for a core has been collected. +uint32_t G_updated_core_mask = 0; + +// Mask to indicate when an empath error has been detected and empath data +// should be ignored. Core bits are cleared when empath data is collected +// without error. +uint32_t G_empath_error_core_mask = 0; + +//Global G_present_cores is bitmask of all cores +//(1 = present, 0 = not present. Core 0 has the most significant bit) +uint32_t G_present_cores = 0; + +//Global double buffering for fast core data collection. +GPE_BUFFER(gpe_fast_core_data_t G_fast_core_data[NUM_FAST_CORE_DATA_BUFF]) = {{0}}; + +//Pointer to the latest fast core data that will be used by AMEC code. +GPE_BUFFER(gpe_fast_core_data_t * G_read_fast_core_data_ptr) = { &G_fast_core_data[0] }; + +//Pointer used by GPE code to write fast core data. +GPE_BUFFER(gpe_fast_core_data_t * G_write_fast_core_data_ptr) = { &G_fast_core_data[1] }; + +//Globals structure for gpe get chip data fast parms. +//The Gpe parameter fields are set up each time before collect data start. +GPE_BUFFER(GpeGetChipDataFastParms G_chip_data_fast_parms); + +//Pore flex request for GPE job. The initialization +//will be done one time during pore flex create. +PoreFlex G_fast_cores_req; + +//Global G_present_hw_cores is bitmask of all hardware cores +//(1 = present, 0 = not present. Core 0 has the most significant bit) +uint32_t G_present_hw_cores = 0; + +//OCC to HW core id mapping array +uint8_t G_occ2hw_core_id[MAX_NUM_HW_CORES] = { 1, 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14, 0, 7, 8, 15 }; + +//HW to OCC core id mapping array +uint8_t G_hw2occ_core_id[MAX_NUM_HW_CORES] = { 12, 0, 1, 2, 3, 4, 5, 13, 14, 6, 7, 8, 9, 10, 11, 15 }; + +//Flag to keep tract of one time trace for GPE running case +//for task core data. +bool G_queue_not_idle_traced = FALSE; + +//Flag to keep tract of one time trace for GPE running case +//for Fast core data. +bool G_fast_core_queue_not_idle_traced = FALSE; + +// Global to track the maximum time elapsed between pore flex schedules of +// per core get_per_core_data tasks. The array is indexed by core number. +uint32_t G_get_per_core_data_max_schedule_intervals[MAX_NUM_HW_CORES] = {0,}; + +// Declaration of debug functions +#ifdef PROC_DEBUG +void print_core_data_sensors(uint8_t core); +void print_core_status(uint8_t core); +void print_fast_core_data(void); +#endif + +// Function Specification +// +// Name: task_core_data +// +// Description: Collect bulk core data for all cores in specified range. +// The task used for core data collection will be split into two +// individual task instances. The task function is the same but it needs +// to gather data for different sets of cores. +// +// +// End Function Specification + +void task_core_data( task_t * i_task ) +{ + + errlHndl_t l_err = NULL; //Error handler + tracDesc_t l_trace = NULL; //Temporary trace descriptor + int rc = 0; //return code + bulk_core_data_task_t * l_bulk_core_data_ptr = (bulk_core_data_task_t *)i_task->data_ptr; + GpeGetCoreDataParms * l_parms = (GpeGetCoreDataParms *)(l_bulk_core_data_ptr->gpe_req.parameter); + gpe_bulk_core_data_t * l_temp = NULL; + + do + { + //First, check to see if the previous GPE request still running + //A request is considered idle if it is not attached to any of the + //asynchronous request queues + if( !(async_request_is_idle(&l_bulk_core_data_ptr->gpe_req.request)) ) + { + //This should not happen unless there's a problem + //Trace 1 time + if( !G_queue_not_idle_traced ) + { + TRAC_ERR("Core data GPE is still running \n"); + G_queue_not_idle_traced = TRUE; + } + break; + } + + //Need to complete collecting data for all assigned cores from previous interval + //and tick 0 is the current tick before collect data again. + if( (l_bulk_core_data_ptr->current_core == l_bulk_core_data_ptr->end_core) + && + ((CURRENT_TICK & (MAX_NUM_TICKS - 1)) != 0) ) + { + PROC_DBG("Not collect data. Need to wait for tick.\n"); + break; + } + + //Check to see if the previously GPE request has successfully completed + //A request is not considered complete until both the engine job + //has finished without error and any callback has run to completion. + + if( async_request_completed(&l_bulk_core_data_ptr->gpe_req.request) + && + CORE_PRESENT(l_bulk_core_data_ptr->current_core) ) + { + //If the previous GPE request succeeded then swap core_data_ptr + //with the global one. The gpe routine will write new data into + //a buffer that is not being accessed by the RTLoop code. + + PROC_DBG( "Swap core_data_ptr [%x] with the global one\n", + l_bulk_core_data_ptr->current_core ); + + //debug only +#ifdef PROC_DEBUG + print_core_status(l_bulk_core_data_ptr->current_core); + print_core_data_sensors(l_bulk_core_data_ptr->current_core); +#endif + + l_temp = l_bulk_core_data_ptr->core_data_ptr; + l_bulk_core_data_ptr->core_data_ptr = + G_core_data_ptrs[l_bulk_core_data_ptr->current_core]; + G_core_data_ptrs[l_bulk_core_data_ptr->current_core] = l_temp; + + //Core data has been collected so set the bit in global mask. + //AMEC code will know which cores to update sensors for. AMEC is + //responsible for clearing the bit later on. + G_updated_core_mask |= CORE0_PRESENT_MASK >> (l_bulk_core_data_ptr->current_core); + + // Presumptively clear the empath error mask + G_empath_error_core_mask &= + ~(CORE0_PRESENT_MASK >> (l_bulk_core_data_ptr->current_core)); + + // The gpe_data collection code has to handle the workaround for + // HW280375. Two new flags have been added to the OHA_RO_STATUS_REG + // image to indicate whether the EMPATH collection failed, and + // whether it was due to an "expected" error that we can ignore + // (we can ignore the data as well), or an "unexpected" error that + // we will create an informational log one time. + // + // The "expected" errors are very rare in practice, in fact we may + // never even see them unless running a specific type of workload. + // If you want to test the handling of expected errors compile the + // GPE code with -DINJECT_HW280375_ERRORS which will inject an error + // approximately every 1024 samples + // + // To determine if the expected error has occurred inspect the + // CoreDataOha element of the CoreData structure written by the GPE + // core data job. The OHA element contains the oha_ro_status_reg. + // Inside the OHA status register is a 16 bit reserved field. + // gpe_data.h defines two masks that can be applied against the + // reserved field to check for these errors: + // CORE_DATA_EXPECTED_EMPATH_ERROR + // CORE_DATA_UNEXPECTED_EMPATH_ERROR + // Also, a 4-bit PCB parity + error code is saved at bit position: + // CORE_DATA_EMPATH_ERROR_LOCATION, formally the length is + // specified by: CORE_DATA_EMPATH_ERROR_BITS + gpe_bulk_core_data_t *l_core_data = + G_core_data_ptrs[l_bulk_core_data_ptr->current_core]; + + // We will trace the errors, but only a certain number of + // times, we will only log the unexpected error once. +#define OCC_EMPATH_ERROR_THRESH 10 + static uint32_t L_expected_emp_err_cnt = 0; + static uint32_t L_unexpected_emp_err_cnt = 0; + + // Check the reserved field for the expected or the unexpected error flag + if ((l_core_data->oha.oha_ro_status_reg.fields._reserved0 & CORE_DATA_EXPECTED_EMPATH_ERROR) + || + (l_core_data->oha.oha_ro_status_reg.fields._reserved0 & CORE_DATA_UNEXPECTED_EMPATH_ERROR)) + { + // Indicate empath error on current core + G_empath_error_core_mask |= + CORE0_PRESENT_MASK >> (l_bulk_core_data_ptr->current_core); + + // Save the high and low order words of the OHA status reg + uint32_t l_oha_reg_high = l_core_data->oha.oha_ro_status_reg.words.high_order; + uint32_t l_oha_reg_low = l_core_data->oha.oha_ro_status_reg.words.low_order; + + // Handle each error case + if ((l_core_data->oha.oha_ro_status_reg.fields._reserved0 & CORE_DATA_EXPECTED_EMPATH_ERROR) + && + (L_expected_emp_err_cnt < OCC_EMPATH_ERROR_THRESH)) + { + L_expected_emp_err_cnt++; + TRAC_IMP("Expected empath collection error occurred %d time(s)! Core = %d", + L_expected_emp_err_cnt, + l_bulk_core_data_ptr->current_core); + TRAC_IMP("OHA status register: 0x%4.4x%4.4x", + l_oha_reg_high, l_oha_reg_low); + } + + if ((l_core_data->oha.oha_ro_status_reg.fields._reserved0 & CORE_DATA_UNEXPECTED_EMPATH_ERROR) + && + (L_unexpected_emp_err_cnt < OCC_EMPATH_ERROR_THRESH)) + { + L_unexpected_emp_err_cnt++; + TRAC_ERR("Unexpected empath collection error occurred %d time(s)! Core = %d", + L_unexpected_emp_err_cnt, + l_bulk_core_data_ptr->current_core); + TRAC_ERR("OHA status register: 0x%4.4x%4.4x", + l_oha_reg_high, l_oha_reg_low); + + // Create and commit an informational error the first + // time this occurs. + if (L_unexpected_emp_err_cnt == 1) + { + TRAC_IMP("Logging unexpected empath collection error 1 time only."); + /* + * @errortype + * @moduleid PROC_TASK_CORE_DATA_MOD + * @reasoncode INTERNAL_HW_FAILURE + * @userdata1 OHA status reg high + * @userdata2 OHA status reg low + * @userdata4 ERC_PROC_CORE_DATA_EMPATH_ERROR + * @devdesc An unexpected error occurred while + * collecting core empath data. + */ + l_err = createErrl( + PROC_TASK_CORE_DATA_MOD, //modId + INTERNAL_HW_FAILURE, //reason code + ERC_PROC_CORE_DATA_EMPATH_ERROR, //Extended reason code + ERRL_SEV_INFORMATIONAL, //Severity + NULL, //Trace + DEFAULT_TRACE_SIZE, //Trace Size + l_oha_reg_high, //userdata1 + l_oha_reg_low); //userdata2 + + commitErrl(&l_err); + } + } + } + } + + // If the core is not present, then we need to point to the empty G_core_data + // so that we don't use old/stale data from a leftover G_core_data + if( !CORE_PRESENT(l_bulk_core_data_ptr->current_core)) + { + G_core_data_ptrs[l_bulk_core_data_ptr->current_core] = &G_core_data[14]; + } + + //Update current core + if ( l_bulk_core_data_ptr->current_core >= l_bulk_core_data_ptr->end_core ) + { + l_bulk_core_data_ptr->current_core = l_bulk_core_data_ptr->start_core; + } + else + { + l_bulk_core_data_ptr->current_core++; + } + + //If core is not present then skip it. This task assigned to this core will + //be idle during this time it would have collected the data. + if( CORE_PRESENT(l_bulk_core_data_ptr->current_core) ) + { + PROC_DBG("Schedule PoreFlex OCC core [%x] or HW core [%x]\n", + l_bulk_core_data_ptr->current_core, CORE_OCC2HW(l_bulk_core_data_ptr->current_core)); + + //1. Setup the get core data parms + l_parms->config = + ((uint64_t) CORE0_PRESENT_MASK_GPE) >> (CORE_OCC2HW(l_bulk_core_data_ptr->current_core)); + + if( (cfam_id() == CFAM_CHIP_ID_MURANO_10) + || (cfam_id() == CFAM_CHIP_ID_MURANO_11) + || (cfam_id() == CFAM_CHIP_ID_MURANO_12) ) + { + // Due to HW243646 & HW243942 fallout, we will not be collecting EX core + // activity counter scoms until Murano DD1.3 + l_parms->select = GPE_GET_CORE_DATA_DTS_CPM | GPE_GET_CORE_DATA_PCB_SLAVE; + } + else + { + l_parms->select = GPE_GET_CORE_DATA_ALL; + } + + l_parms->data = (uint32_t) l_bulk_core_data_ptr->core_data_ptr; + + // Static array to record the last timestamp a get_per_core_data task was + // scheduled for a core. + static SsxTimebase L_last_get_per_core_data_scheduled_time[MAX_NUM_HW_CORES] = {0,}; + uint8_t l_current_core = l_bulk_core_data_ptr->current_core; + SsxTimebase l_now = ssx_timebase_get(); + // If the last scheduled timestamp is 0, record time and continue to schedule + if (L_last_get_per_core_data_scheduled_time[l_current_core] == 0) + { + L_last_get_per_core_data_scheduled_time[l_current_core] = l_now; + } + else + { + // Calculate elapsed time in usecs since last get_per_core_data + // task for the current core was scheduled. + uint32_t l_elapsed_us = + (uint32_t)((l_now - L_last_get_per_core_data_scheduled_time[l_current_core])/ + (SSX_TIMEBASE_FREQUENCY_HZ/1000000)); + // Save the last scheduled timestamp + L_last_get_per_core_data_scheduled_time[l_current_core] = l_now; + // If the new elapsed time is greater than what is currently saved, + // save the larger time. + if (G_get_per_core_data_max_schedule_intervals[l_current_core] < l_elapsed_us) + { + G_get_per_core_data_max_schedule_intervals[l_current_core] = l_elapsed_us; + TRAC_INFO("New max get_per_core_data interval: core=%d, interval(us)=%d", + l_current_core, l_elapsed_us); + } + // Also sniff if the request has actually completed, it is checked above but + // the schedule proceeds regardless which could be dangerous... + if (!async_request_completed(&l_bulk_core_data_ptr->gpe_req.request)) + { + TRAC_ERR("Async get_per_core_data task for core=%d not complete!", + l_current_core); + } + } + + // The PCBS heartbeat timer may time out even though we are scheduling + // the get_per_core_data task for each core every 2ms. Reason at time + // of this code change is still unknown but reproducible. We are going + // to getscom the PMSTATEHISTOCC register (PCBS_PMSTATEHISTOCC_REG) for + // each configured core before scheduling the PORE job to try and make + // sure the heartbeat doesn't expire. + // Recent tests show the heartbeat is holding steady so the getscom is + // commented out and incomplete, the core number needs to be converted + // to a hardware core number if this code is activated. + //uint64_t l_dont_care = 0; + //uint32_t core = CORE_CHIPLET_ADDRESS(PCBS_PMSTATEHISTOCC_REG, ???); + //getscom(address???, &l_dont_care); + + //2. Port flex schedule gpe_get_per_core_data + // Check pore_flex_schedule return code if error + // then request OCC reset. + + rc = pore_flex_schedule( &l_bulk_core_data_ptr->gpe_req ); + if( rc != 0 ) + { + //Error in schedule gpe get core data + TRAC_ERR("Failed PoreFlex schedule core [%x] \n", rc); + + /* + * @errortype + * @moduleid PROC_TASK_CORE_DATA_MOD + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 pore_flex_schedule return code + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc SSX PORE related failure + */ + l_err = createErrl( + PROC_TASK_CORE_DATA_MOD, //modId + SSX_GENERIC_FAILURE, //reasoncode + OCC_NO_EXTENDED_RC, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + l_trace, //TODO: create l_trace //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //userdata1 + 0 //userdata2 + ); + + // commit error log + REQUEST_RESET(l_err); + break; + } + } + } + while(0); + + return; +} + + +// Function Specification +// +// Name: proc_core_init +// +// Description: Initialize structure for collecting core data. It +// needs to be run in occ main and before RTLoop started. +// +// End Function Specification + +void proc_core_init( void ) +{ + errlHndl_t l_err = NULL; //Error handler + tracDesc_t l_trace = NULL; //Temporary trace descriptor + int rc = 0; //Return code + + do + { + //Before RTLoop starts to collect data. We need to determine what cores + //are present and configured. We have a register that has information + //of all cores that have been deconfigured in the chip so we need to read that. + + G_present_hw_cores = in32(PMC_CORE_DECONFIGURATION_REG); + + //Inverse the bitmask of the deconfigured register to get present + //cores and save it in the global present hardware cores. + G_present_hw_cores = ~G_present_hw_cores & HW_CORES_MASK; + + //Convert hardware core numering to OCC core numering. + G_present_cores = ((G_present_hw_cores & LO_CORES_MASK) << 1) | + ((G_present_hw_cores & HI_CORES_MASK) << 3); + + PROC_DBG("G_present_hw_cores =[%x] and G_present_cores =[%x] \n", + G_present_hw_cores, G_present_cores); + + //Initializes low cores data PoreFlex object + rc = pore_flex_create( &G_low_cores.gpe_req, //gpe_req for the task + &G_pore_gpe0_queue, //queue + gpe_get_per_core_data, //entry point + //parm for the task + (uint32_t) &G_low_cores_data_parms, + SSX_WAIT_FOREVER, // no timeout + NULL, //callback + NULL, //callback argument + 0 ); //options + if( rc ) + { + //If fail to create pore flex object then there is a problem. + TRAC_ERR("Fail to create low cores poreFlex object[0x%x]", rc ); + + /* + * @errortype + * @moduleid PROC_CORE_INIT_MOD + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 pore_flex_create return code + * @userdata4 ERC_LOW_CORE_PORE_FLEX_CREATE_FAILURE + * @devdesc Failure to create low cores poreflex object + */ + l_err = createErrl( + PROC_CORE_INIT_MOD, //modId + SSX_GENERIC_FAILURE, //reasoncode + ERC_LOW_CORE_PORE_FLEX_CREATE_FAILURE, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + l_trace, //TODO: create l_trace //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //userdata1 + 0 //userdata2 + ); + + // commit error log + REQUEST_RESET(l_err); + break; + } + + //Initializes existing PoreFlex object for high cores data + rc = pore_flex_create( &G_high_cores.gpe_req, //gpe_req for the task + &G_pore_gpe0_queue, //queue + gpe_get_per_core_data, //entry point + //parm for the task + (uint32_t) &G_high_cores_data_parms, + SSX_WAIT_FOREVER, //no timeout + NULL, //callback + NULL, //callback argument + 0 ); //options + if( rc ) + { + //If fail to create pore flex object then there is a problem. + TRAC_ERR("Fail to create high cores poreFlex object[0x%x]", rc ); + + /* + * @errortype + * @moduleid PROC_CORE_INIT_MOD + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 pore_flex_create return code + * @userdata4 ERC_HIGH_CORE_PORE_FLEX_CREATE_FAILURE + * @devdesc Failure to create high core poreFlex object + */ + l_err = createErrl( + PROC_CORE_INIT_MOD, //modId + SSX_GENERIC_FAILURE, //reasoncode + ERC_HIGH_CORE_PORE_FLEX_CREATE_FAILURE, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + l_trace, //TODO: create l_trace //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //userdata1 + 0 //userdata2 + ); + + // commit error log + REQUEST_RESET(l_err); + break; + } + + //Initializes PoreFlex object for fast core data + rc = pore_flex_create( &G_fast_cores_req, //gpe_req for the task + &G_pore_gpe0_queue, //queue + gpe_get_core_data_fast, //entry point + //parm for the task + (uint32_t) &G_chip_data_fast_parms, + SSX_WAIT_FOREVER, //no timeout + NULL, //callback + NULL, //callback argument + 0 ); //options + if( rc ) + { + //If fail to create pore flex object then there is a problem. + TRAC_ERR("Fail to create fast cores poreFlex object[0x%x]", rc ); + + /* + * @errortype + * @moduleid PROC_CORE_INIT_MOD + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 pore_flex_create return code + * @userdata4 ERC_FAST_CORE_PORE_FLEX_CREATE_FAILURE + * @devdesc Failure to create fast core data poreFlex object + */ + l_err = createErrl( + PROC_CORE_INIT_MOD, //modId + SSX_GENERIC_FAILURE, //reasoncode + ERC_FAST_CORE_PORE_FLEX_CREATE_FAILURE, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + l_trace, //TODO: create l_trace point //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //userdata1 + 0 //userdata2 + ); + + // commit error log + REQUEST_RESET(l_err); + break; + } + + } while(0); + + // Initialize the core data control structures at the same time + proc_core_data_control_init(); + + return; +} + +// Function Specification +// +// Name: task_fast_core_data +// +// Description: Collect fast core data for all configured cores on every tick. +// +// End Function Specification + +void task_fast_core_data( task_t * i_task ) +{ + + errlHndl_t l_err = NULL; //Error handler + tracDesc_t l_trace = NULL; //Temporary trace descriptor + int rc = 0; //Return code + gpe_fast_core_data_t * l_temp = NULL; + uint32_t l_pres_hw_cores; + + //poll the pmc deconfig register for newly deconfigured cores + l_pres_hw_cores = (~in32(PMC_CORE_DECONFIGURATION_REG)) & HW_CORES_MASK; + if(l_pres_hw_cores != G_present_hw_cores) + { + TRAC_IMP("Present cores changed. old_hw_mask[0x%04x] new_hw_mask[0x%04x]", + G_present_hw_cores, l_pres_hw_cores); + + //update our global core presence masks + G_present_hw_cores = l_pres_hw_cores; + G_present_cores = ((l_pres_hw_cores & LO_CORES_MASK) << 1) | + ((l_pres_hw_cores & HI_CORES_MASK) << 3); + } + + do + { + //Check to see if the previous GPE request still running + if( !(async_request_is_idle(&G_fast_cores_req.request)) ) + { + //This should not happen unless there's a problem + //Trace 1 time + if( !G_fast_core_queue_not_idle_traced ) + { + TRAC_ERR("GPE is still running \n"); + G_fast_core_queue_not_idle_traced = TRUE; + } + break; + } + + //Check to see if the previosuly GPE request has been succeeded + if( async_request_completed(&G_fast_cores_req.request) ) + { + //If the previous GPE request succeeded then swap the + //G_read_fast_core_data_ptr with the G_write_fast_core_data_ptr. + + PROC_DBG("Fast core data GPE request has been succeeded.\n"); + + #ifdef PROC_DEBUG + print_fast_core_data(); + #endif + + l_temp = G_write_fast_core_data_ptr; + G_write_fast_core_data_ptr = G_read_fast_core_data_ptr; + G_read_fast_core_data_ptr = l_temp; + } + + //Setup the get fast core data parms + G_chip_data_fast_parms.config = (uint64_t) (((uint64_t) G_present_hw_cores) << 32); + G_chip_data_fast_parms.select = GPE_GET_CORE_DATA_FAST_FREQ_TARGET; + G_chip_data_fast_parms.data = (uint32_t) G_write_fast_core_data_ptr; + + //Port flex schedule gpe_get_core_data_fast + //Check pore_flex_schedule return code if error + //then request OCC reset. + + rc = pore_flex_schedule( &G_fast_cores_req ); + if( rc != 0 ) + { + //Error in schedule gpe get fast core data + TRAC_ERR("Failed PoreFlex schedule fast core data [%x] \n", rc); + + /* + * @errortype + * @moduleid PROC_TASK_FAST_CORE_DATA_MOD + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 pore_flex_schedule return code + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc SSX PORE related failure + */ + l_err = createErrl( + PROC_TASK_FAST_CORE_DATA_MOD, //modId + SSX_GENERIC_FAILURE, //reasoncode + OCC_NO_EXTENDED_RC, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + l_trace, //TODO: create l_trace point //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //userdata1 + 0 ); //userdata2 + + // commit error log + REQUEST_RESET(l_err); + break; + } + } while(0); + + return; +} + +// Function Specification +// +// Name: proc_get_bulk_core_data_ptr +// +// Description: Returns a pointer to the most up-to-date bulk core data for +// the core associated with the specified OCC core id. Returns +// NULL for core ID outside the range of 0 to 11. +// +// End Function Specification +gpe_bulk_core_data_t * proc_get_bulk_core_data_ptr( const uint8_t i_occ_core_id ) +{ + //The caller needs to send in a valid OCC core id. Since type is uchar + //so there is no need to check for case less than 0. + //If core id is invalid then returns NULL. + + if( i_occ_core_id <= 11 ) + { + //Returns a pointer to the most up-to-date bulk core data. + return G_core_data_ptrs[i_occ_core_id]; + } + else + { + //Core id outside the range + TRAC_ERR("Invalid OCC core id [0x%x]", i_occ_core_id); + return( NULL ); + } +} + +// Function Specification +// +// Name: proc_get_fast_core_data_ptr +// +// Description: Returns a pointer to the most up-to-date fast core data +// +// End Function Specification +gpe_fast_core_data_t * proc_get_fast_core_data_ptr( void ) +{ + //Returns a pointer to the most up-to-date fast core data. + //Core data is organized is organized in hardware scheme. + + return G_read_fast_core_data_ptr; +} + +#ifdef PROC_DEBUG +// Function Specification +// +// Name: print_core_data_sensors +// +// Description: Print out sensors data of a specified core in the chip +// +// End Function Specification + +void print_core_data_sensors(uint8_t core) +{ + gpe_bulk_core_data_t * l_core_data = proc_get_bulk_core_data_ptr(core); + + if( l_core_data != NULL ) + { + PROC_DBG("\n-------------------------------\n"); + PROC_DBG("Core [%x] Sensors Data \n", core); + // TODO: Commented these out b/c they take too long to run in task. + // Consider moving this to an applet + //dumpHexString(&l_core_data->sensors_tod, sizeof(l_core_data->sensors_tod), "Sensor TOD"); + //dumpHexString(&l_core_data->sensors_v0, sizeof(l_core_data->sensors_v0), "Sensor VO"); + //dumpHexString(&l_core_data->sensors_v1, sizeof(l_core_data->sensors_v1), "Sensor V1"); + //dumpHexString(&l_core_data->sensors_v8, sizeof(l_core_data->sensors_v8), "Sensor V8"); + //dumpHexString(&l_core_data->sensors_v9, sizeof(l_core_data->sensors_v9), "Sensor V9"); + PROC_DBG("\n"); + } + else + { + PROC_DBG("\n G_core_data_ptrs[%x] is NULL. This should not happen.\n", core); + } + return; +} + +// Function Specification +// +// Name: print_core_status +// +// Description: Print out information of a specified core in the chip +// +// End Function Specification + +void print_core_status(uint8_t core) +{ + gpe_bulk_core_data_t * l_core_data = proc_get_bulk_core_data_ptr(core); + + if( l_core_data != NULL ) + { + PROC_DBG("\n-------------------------\n"); + PROC_DBG("Core [%x] status \n", core); + // TODO: Commented these out b/c they take too long to run in task. + // Consider moving this to an applet + //dumpHexString(&l_core_data->core_tod, sizeof(l_core_data->core_tod), "Core TOD"); + //dumpHexString(&l_core_data->core_raw_cycles, sizeof(l_core_data->core_raw_cycles), "Core Raw Cycles"); + //dumpHexString(&l_core_data->core_run_cycles, sizeof(l_core_data->core_run_cycles), "Run Cycles"); + //dumpHexString(&l_core_data->core_dispatch, sizeof(l_core_data->core_dispatch), "Core Dispatch"); + //dumpHexString(&l_core_data->core_completion, sizeof(l_core_data->core_completion), "Core Completion"); + //dumpHexString(&l_core_data->core_workrate, sizeof(l_core_data->core_workrate), "Core Workrate"); + //dumpHexString(&l_core_data->core_spurr, sizeof(l_core_data->core_spurr), "Core Spurr"); + //dumpHexString(&l_core_data->core_mem_hler_a, sizeof(l_core_data->core_mem_hler_a), "Mem A"); + //dumpHexString(&l_core_data->core_mem_hler_b, sizeof(l_core_data->core_mem_hler_b), "Mem B"); + //dumpHexString(&l_core_data->mem_tod, sizeof(l_core_data->mem_tod), "Mem TOD"); + //dumpHexString(&l_core_data->mem_raw_cycles, sizeof(l_core_data->mem_raw_cycles), "Mem Raw Cycles"); + PROC_DBG("\n"); + } + else + { + PROC_DBG("\n G_core_data_ptrs[%x] is NULL. This should not happen.\n", core); + } + return; +} + +// Function Specification +// +// Name: print_fast_core_data +// +// Description: Print out fast core data of the chip +// +// End Function Specification + +void print_fast_core_data(void) +{ + gpe_fast_core_data_t * l_fast_core_data = proc_get_fast_core_data_ptr(); + + if( l_fast_core_data != NULL ) + { + PROC_DBG("\n---------------------------\n"); + // TODO: Commented these out b/c they take too long to run in task. + // Consider moving this to an applet + //dumpHexString(&l_fast_core_data->tod, sizeof(l_fast_core_data->tod), "Fast Core Data TOD"); + //dumpHexString(&l_fast_core_data->core_data, sizeof(fast_core_data_t) * MAX_NUM_HW_CORES, "Fast Core Data"); + PROC_DBG("\n"); + } + else + { + PROC_DBG("\n G_read_fast_core_data_ptr is NULL. This should not happen.\n"); + } + return; +} +#endif + diff --git a/src/occ_405/proc/proc_data.h b/src/occ_405/proc/proc_data.h new file mode 100755 index 0000000..03dc6b2 --- /dev/null +++ b/src/occ_405/proc/proc_data.h @@ -0,0 +1,179 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/proc/proc_data.h $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* [+] 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 */ + +#ifndef _PROC_DATA_H +#define _PROC_DATA_H + +#include <occ_common.h> +#include <ssx.h> +#include "rtls.h" +#include "gpe_data.h" + +//Returns 0 if the specified core is not present. Otherwise, returns none-zero. +#define CORE_PRESENT(occ_core_id) \ + ((CORE0_PRESENT_MASK >> occ_core_id) & G_present_cores) + +//Takes an OCC core id and converts it to a core id that +//can be used by the hardware. The caller needs to send in +//a valid core id. Since type is uchar so there is no need to check for +//case less than 0. If core id is invalid then returns unconfigured core 16. +#define CORE_OCC2HW(occ_core_id) \ + ((occ_core_id <= 15) ? G_occ2hw_core_id[occ_core_id] : 16) + +//Takes a hardware core id and returns a OCC core id. +//The caller needs to send in a valid core id. Since type is uchar so +//there is no need to check for case less than 0. If core id +//is invalid then returns unconfigured core 16. +#define CORE_HW2OCC(hw_core_id) \ + ((hw_core_id <= 15) ? G_hw2occ_core_id[hw_core_id] : 16) + +#define ALL_CORES_MASK 0xffff0000 +#define CORE0_PRESENT_MASK 0x80000000ul +#define CORE0_PRESENT_MASK_GPE 0x8000000000000000ull + +#define MAX_NUM_HW_CORES 16 +#define MAX_NUM_FW_CORES 12 + +#define THREADS_PER_CORE 8 +#define MAX_MEM_PARTS 4 + +#define NUM_FAST_CORE_DATA_BUFF 2 +#define NUM_CORE_DATA_BUFF 7 +#define NUM_CORE_DATA_DOUBLE_BUF 2 +#define NUM_CORE_DATA_EMPTY_BUF 1 + +#define LO_CORES_MASK 0x7e000000 +#define HI_CORES_MASK 0x007e0000 +#define HW_CORES_MASK 0xffff0000 + +enum eOccProcCores +{ + CORE_0 = 0, + CORE_1 = 1, + CORE_2 = 2, + CORE_3 = 3, + CORE_4 = 4, + CORE_5 = 5, + CORE_6 = 6, + CORE_7 = 7, + CORE_8 = 8, + CORE_9 = 9, + CORE_10 = 10, + CORE_11 = 11, +}; + +typedef CoreData gpe_bulk_core_data_t; + +//Processor data collect structures used for task data pointers +//gpe_req.request.parameter points to GpeGetCoreDataParms +struct bulk_core_data_task { + uint8_t start_core; + uint8_t current_core; + uint8_t end_core; + gpe_bulk_core_data_t * core_data_ptr; + PoreFlex gpe_req; +} __attribute__ ((__packed__)); +typedef struct bulk_core_data_task bulk_core_data_task_t; + +//Only PCBS_LOCAL_PSTATE_FREQ_TARGET_STATUS_REG register is being +//collected at this time. Other register will be added when needed. +struct fast_core_data { + uint64_t pcbs_lpstate_freq_target_sr; +} __attribute__ ((__packed__)); +typedef struct fast_core_data fast_core_data_t; + +//gpe fast core data structure +struct gpe_fast_core_data { + uint32_t tod; + uint32_t reserved; + fast_core_data_t core_data[MAX_NUM_HW_CORES]; +} __attribute__ ((__packed__)); +typedef struct gpe_fast_core_data gpe_fast_core_data_t; + +//Global low and high cores structures used for task data pointers +extern bulk_core_data_task_t G_low_cores; +extern bulk_core_data_task_t G_high_cores; + +//Global G_present_cores is bitmask of all OCC core numbering +extern uint32_t G_present_cores; + +//Global G_present_hw_cores is bitmask of all hardware cores +extern uint32_t G_present_hw_cores; +extern uint8_t G_occ2hw_core_id[MAX_NUM_HW_CORES]; +extern uint8_t G_hw2occ_core_id[MAX_NUM_HW_CORES]; + +//AMEC needs to know when data for a core has been collected. +extern uint32_t G_updated_core_mask; + +// External reference to empath error mask +extern uint32_t G_empath_error_core_mask; + +//Returns 0 if the specified core is not present. Otherwise, returns none-zero. +#define CORE_PRESENT(occ_core_id) \ + ((CORE0_PRESENT_MASK >> occ_core_id) & G_present_cores) + +//Returns 0 if the specified core is not updated. Otherwise, returns none-zero. +#define CORE_UPDATED(occ_core_id) \ + ((CORE0_PRESENT_MASK >> occ_core_id) & G_updated_core_mask) + +//Returns 0 if the specified core is not updated. Otherwise, returns none-zero. +#define CLEAR_CORE_UPDATED(occ_core_id) \ + G_updated_core_mask &= ~(CORE0_PRESENT_MASK >> occ_core_id) + +// Evaluates to true if an empath collection error has occurred on a core +#define CORE_EMPATH_ERROR(occ_core_id) \ + ((CORE0_PRESENT_MASK >> occ_core_id) & G_empath_error_core_mask) + +//Takes an OCC core id and converts it to a core id that +//can be used by the hardware. The caller needs to send in +//a valid core id. Since type is uchar so there is no need to check for +//case less than 0. If core id is invalid then returns unconfigured core 16. +#define CORE_OCC2HW(occ_core_id) \ + ((occ_core_id <= 15) ? G_occ2hw_core_id[occ_core_id] : 16) + +//Takes a hardware core id and returns a OCC core id. +//The caller needs to send in a valid core id. Since type is uchar so +//there is no need to check for case less than 0. If core id +//is invalid then returns unconfigured core 16. +#define CORE_HW2OCC(hw_core_id) \ + ((hw_core_id <= 15) ? G_hw2occ_core_id[hw_core_id] : 16) + +//Collect bulk core data for all cores in specified range +void task_core_data( task_t * i_task ); + +//Initialize structures for collecting core data. +void proc_core_init( void ) INIT_SECTION; + +//Collect fast core data for all configured cores on every tick +void task_fast_core_data( task_t * i_task ); + +//Returns a pointer to the most up-to-date bulk core data for the core +//associated with the specified OCC core id. +gpe_bulk_core_data_t * proc_get_bulk_core_data_ptr( const uint8_t i_occ_core_id ); + +//Returns a pointer to the most up-to-date fast core data +gpe_fast_core_data_t * proc_get_fast_core_data_ptr( void ); + +#endif //_PROC_DATA_H diff --git a/src/occ_405/proc/proc_data_control.c b/src/occ_405/proc/proc_data_control.c new file mode 100755 index 0000000..8e8a3c2 --- /dev/null +++ b/src/occ_405/proc/proc_data_control.c @@ -0,0 +1,264 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ/proc/proc_data_control.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* [+] 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 "proc_data.h" +#include "pgp_async.h" +#include "threadSch.h" +#include "pmc_register_addresses.h" +#include "proc_data_service_codes.h" +#include "occ_service_codes.h" +#include "errl.h" +#include "trac.h" +#include "rtls.h" +#include "apss.h" +#include "state.h" +#include "gpe_control.h" +#include "occ_sys_config.h" + +// Pore flex request for GPE job. The initialization will be done one time +// during pore flex create. +PoreFlex G_core_data_control_req; + +// Global double buffering for core data control +GPE_BUFFER(PcbsPstateRegs G_core_data_control_a[MAX_NUM_HW_CORES]) = {{{0}}}; +GPE_BUFFER(PcbsPstateRegs G_core_data_control_b[MAX_NUM_HW_CORES]) = {{{0}}}; + +// Pointer to the core data control that will be used by GPE engine. +GPE_BUFFER(PcbsPstateRegs * G_core_data_control_gpewrite_ptr) = { &G_core_data_control_a[0] }; + +// Pointer to the core data control that will be written to by the OCC FW. +GPE_BUFFER(PcbsPstateRegs * G_core_data_control_occwrite_ptr) = { &G_core_data_control_b[0] }; + +// The Gpe parameter fields are set up each time before the GPE starts. +GPE_BUFFER(GpeSetPstatesParms G_core_data_control_parms); + +// Function Specification +// +// Name: proc_set_pstate +// +// Description: Function to demonstrate setting Pstates to all cores +// Should only be run from RTL +// +// End Function Specification +void proc_set_pstate_all(Pstate i_pstate) +{ + uint8_t l_chiplet = 0; + + for(; l_chiplet<MAX_NUM_HW_CORES; l_chiplet++) + { + set_chiplet_pstate(G_core_data_control_occwrite_ptr, + l_chiplet, + i_pstate, + i_pstate); + } + + PROC_DBG("Setting Pstates to %d\n",i_pstate); +} + + +// Function Specification +// +// Name: proc_set_core_pstate +// +// Description: Function to demonstrate setting Pstates to all cores +// Should only be run from RTL +// +// End Function Specification +void proc_set_core_pstate(Pstate i_pstate, uint8_t i_core) +{ + set_chiplet_pstate(G_core_data_control_occwrite_ptr, + CORE_OCC2HW(i_core), + i_pstate, + i_pstate); +} + +// Function Specification +// +// Name: proc_set_core_bounds +// +// Description: Function to set core pmin/pmax +// Should only be run from RTL +// +// End Function Specification +void proc_set_core_bounds(Pstate i_pmin, Pstate i_pmax, uint8_t i_core) +{ + Pstate l_pmax; + uint8_t l_hw_core = CORE_OCC2HW(i_core); + + //don't allow pmax to be set lower than pmin + if(i_pmax < i_pmin) + { + l_pmax = i_pmin; + } + else + { + l_pmax = i_pmax; + } + + set_chiplet_pmax(G_core_data_control_occwrite_ptr, + l_hw_core, + l_pmax); + set_chiplet_pmin(G_core_data_control_occwrite_ptr, + l_hw_core, + i_pmin); +} + + +// Function Specification +// +// Name: proc_core_data_control_init +// +// Description: Initializations needed for core data control task +// +// End Function Specification +void proc_core_data_control_init( void ) +{ + errlHndl_t l_err = NULL; //Error handler + tracDesc_t l_trace = NULL; //Temporary trace descriptor + int rc = 0; //Return code + + do + { + //FIXME: Need to move this object to the PGPE (later phase) + //Initializes PoreFlex object for fast core data + rc = pore_flex_create( &G_core_data_control_req, //gpe_req for the task + &G_pore_gpe0_queue, //queue + gpe_set_pstates, //entry point + (uint32_t) &G_core_data_control_parms, //parm for the task + SSX_WAIT_FOREVER, //no timeout + NULL, //callback + NULL, //callback argument + 0 ); //options + if( rc ) + { + //If fail to create pore flex object then there is a problem. + TRAC_ERR("Fail to create core control poreFlex object[0x%x]", rc ); + + /* + * @errortype + * @moduleid PROC_CORE_INIT_MOD + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 pore_flex_create return code + * @userdata4 ERC_PROC_CONTROL_INIT_FAILURE + * @devdesc Failure to create poreflex object + */ + l_err = createErrl( + PROC_CORE_INIT_MOD, //modId + SSX_GENERIC_FAILURE, //reasoncode + ERC_PROC_CONTROL_INIT_FAILURE, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + l_trace, //TODO: create l_trace //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //userdata1 + 0 //userdata2 + ); + + // commit error log + REQUEST_RESET(l_err); //$gm006 + break; + } + + } while(0); +} + +// Function Specification +// +// Name: task_core_data_control +// +// Description: Control core actuation for all configured cores on every tick. +// +// End Function Specification +void task_core_data_control( task_t * i_task ) +{ + errlHndl_t l_err = NULL; //Error handler + tracDesc_t l_trace = NULL; //Temporary trace descriptor + int rc = 0; //Return code + PcbsPstateRegs * l_temp = NULL; + + do + { + + //Check to see if the previous GPE request still running + if( !(async_request_is_idle(&G_core_data_control_req.request)) ) + { + break; + } + + //Check to see if the previosuly GPE request has been succeeded + if( async_request_completed(&G_core_data_control_req.request) ) + { + //If the previous GPE request succeeded then swap the + //gpewrite ptr with the occwrite ptr. + l_temp = G_core_data_control_occwrite_ptr; + G_core_data_control_gpewrite_ptr = l_temp; + } + + //Setup the core data control parms + G_core_data_control_parms.config = (uint64_t) (((uint64_t) G_present_hw_cores) << 32); + if(G_sysConfigData.system_type.kvm) + { + //Set the chiplet bounds (pmax/pmin) only on sapphire + G_core_data_control_parms.select = GPE_SET_PSTATES_PMBR; + } + else + { + //Set the chiplet pstate request on non-sapphire systems + G_core_data_control_parms.select = GPE_SET_PSTATES_PMCR; + } + + G_core_data_control_parms.regs = (uint32_t) G_core_data_control_gpewrite_ptr; + + rc = pore_flex_schedule( &G_core_data_control_req ); + if( rc != 0 ) + { + TRAC_ERR("Failed PoreFlex schedule core data control [%x] \n", rc); + + /* + * @errortype + * @moduleid PROC_TASK_CORE_DATA_MOD + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 pore_flex_schedule return code + * @userdata4 ERC_PROC_CONTROL_TASK_FAILURE + * @devdesc Failure to schedule poreflex object + */ + l_err = createErrl( + PROC_TASK_CORE_DATA_MOD, //modId + SSX_GENERIC_FAILURE, //reasoncode + ERC_PROC_CONTROL_TASK_FAILURE, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + l_trace, //TODO: create l_trace //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //userdata1 + 0 //userdata2 + ); + + // commit error log + REQUEST_RESET(l_err); + break; + } + } while(0); + + return; +} diff --git a/src/occ_405/proc/proc_data_control.h b/src/occ_405/proc/proc_data_control.h new file mode 100755 index 0000000..6e151e8 --- /dev/null +++ b/src/occ_405/proc/proc_data_control.h @@ -0,0 +1,48 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/proc/proc_data_control.h $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* [+] 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 */ + +#ifndef _PROC_DATA_CONTROL_H +#define _PROC_DATA_CONTROL_H + +#include <occ_common.h> +#include <ssx.h> +#include "rtls.h" +#include "gpe_control.h" + +// Initialze the structures used by the GPE +void proc_core_data_control_init( void ); + +// Task that sets the PMCR, PMBR, PMICR +void task_core_data_control( task_t * i_task ); + +// Function to demonstrate setting Pstates to all cores +void proc_set_pstate_all(Pstate i_pstate); + +// Function to demonstrate setting Pstates one core +void proc_set_core_pstate(Pstate i_pstate, uint8_t i_core); + +// Sets the Pmin/Pmax clip values for one core +void proc_set_core_bounds(Pstate i_pmin, Pstate i_pmax, uint8_t i_core); +#endif diff --git a/src/occ_405/proc/proc_data_service_codes.h b/src/occ_405/proc/proc_data_service_codes.h new file mode 100755 index 0000000..82c5e51 --- /dev/null +++ b/src/occ_405/proc/proc_data_service_codes.h @@ -0,0 +1,41 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/proc/proc_data_service_codes.h $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* [+] 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 */ + +#ifndef _PROC_DATA_SERVICE_CODES_H_ +#define _PROC_DATA_SERVICE_CODES_H_ + +#include <comp_ids.h> + +enum procModuleId +{ + PROC_TASK_CORE_DATA_MOD = PROC_COMP_ID | 0x00, + PROC_CORE_INIT_MOD = PROC_COMP_ID | 0x01, + PROC_TASK_FAST_CORE_DATA_MOD = PROC_COMP_ID | 0x02, + PROC_GPST_INIT_FAILURE_MOD = PROC_COMP_ID | 0x03, + PROC_ENABLE_PSTATES_SMH_MOD = PROC_COMP_ID | 0x04, + PROC_PSTATE_KVM_SETUP_MOD = PROC_COMP_ID | 0x05, +}; + +#endif /* #ifndef _PROC_DATA_SERVICE_CODES_H_ */ diff --git a/src/occ_405/proc/proc_pstate.c b/src/occ_405/proc/proc_pstate.c new file mode 100755 index 0000000..ab225e6 --- /dev/null +++ b/src/occ_405/proc/proc_pstate.c @@ -0,0 +1,1080 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/proc/proc_pstate.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* [+] 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 "ssx.h" +#include "proc_data_service_codes.h" +#include "errl.h" +#include "trac.h" +#include "rtls.h" +#include "dcom.h" +#include "occ_common.h" +#include "state.h" +#include "cmdh_fsp_cmds.h" +#include "cmdhDbugCmd.h" +#include "appletManager.h" +#include "gpsm.h" +#include "pstates.h" +#include "proc_data.h" +#include "proc_pstate.h" +#include "scom.h" + +// GPSM DCM Synchronization States +typedef enum +{ + PROC_GPSM_SYNC_NO_PSTATE_TABLE = 0, + PROC_GPSM_SYNC_PSTATE_TABLE_INSTALLED = 1, + PROC_GPSM_SYNC_READY_TO_ENABLE_MASTER = 2, + PROC_GPSM_SYNC_PSTATE_MASTER_ENABLED = 3, + PROC_GPSM_SYNC_READY_TO_ENABLE_SLAVE = 4, + PROC_GPSM_SYNC_PSTATE_SLAVE_ENABLED = 5, + PROC_GPSM_SYNC_PSTATE_HW_MODE = 6, + PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED = 7, + PROC_GPSM_SYNC_PSTATE_ERROR, +} eProcGpsmDcmSyncStates; + + +// Instance of the PState Table in OCC SRAM. Should be placed in RO section +// so that OCC FW can't corrupt it +GLOBAL_PSTATE_TABLE(G_global_pstate_table); + +// Used for passing DCM Master & Slave States to each other over MBOX +proc_gpsm_dcm_sync_occfw_t G_proc_dcm_sync_state = {0, PROC_GPSM_SYNC_NO_PSTATE_TABLE, PROC_GPSM_SYNC_NO_PSTATE_TABLE,0,0}; + +// Holds Fmax from GPST for ease of proc_freq2pstate calculation +uint32_t G_proc_gpst_fmax = 0; + +// Holds Fmin from GPST for ease of proc_freq2pstate calculation +uint32_t G_proc_gpst_fmin = 0; + +// Holds Pmax from GPST for ease of proc_freq2pstate calculation +int8_t G_proc_gpst_pmax = 0; + +// Remembers if we are a DCM, for DCOM's sake +bool G_isDcm = FALSE; + +// Used for Sapphire +DMA_BUFFER( sapphire_table_t G_sapphire_table ) = {{0}}; + +//KVM throttle reason coming from the frequency voting box. +extern uint8_t G_amec_kvm_throt_reason; + +// Set DCM Sync State +void proc_gpsm_dcm_sync_set_state(eProcGpsmDcmSyncStates i_dcm_sync_state); + +// Tracing out pstate table when it gets installed +void proc_trace_pstate_table_quick(void); + +// Function Specification +// +// Name: proc_is_hwpstate_enabled +// +// Description: Checks DCM Master (or SCM) state to see if Pstate HW Mode +// is enabled. We can check the DCM master state, since DCM +// slave also knows the master and DCM master can't be in this +// state if DCM slave isn't in HW mode +// +// End Function Specification +bool proc_is_hwpstate_enabled(void) +{ + return ((PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED == G_proc_dcm_sync_state.sync_state_master) ? TRUE : FALSE); +} + + +// Function Specification +// +// Name: proc_gpsm_dcm_sync_update_from_mbox +// +// Description: Updates the global variable used for DCM sync based on the +// data that was received via the master/slave mailbox. +// +// Thread: Interrupt; Callback when Slave Inbox is received +// +// End Function Specification +void proc_gpsm_dcm_sync_update_from_mbox(proc_gpsm_dcm_sync_occfw_t * i_dcm_sync_state) +{ + if(!gpsm_dcm_slave_p()) + { + G_proc_dcm_sync_state.sync_state_slave = i_dcm_sync_state->sync_state_slave; + } + else + { + G_proc_dcm_sync_state.sync_state_master = i_dcm_sync_state->sync_state_master; + G_proc_dcm_sync_state.pstate_v = i_dcm_sync_state->pstate_v; + G_proc_dcm_sync_state.pstate_f = i_dcm_sync_state->pstate_f; + } +} + + +// Function Specification +// +// Name: proc_gpsm_dcm_sync_get_state +// +// Description: Return the global variable used for DCM sync +// +// End Function Specification +inline proc_gpsm_dcm_sync_occfw_t proc_gpsm_dcm_sync_get_state(void) +{ + return G_proc_dcm_sync_state; +} + + +// Function Specification +// +// Name: proc_is_dcm +// +// Description: Return if we are a DCM or not +// +// End Function Specification +inline bool proc_is_dcm(void) +{ + return G_isDcm; +} + + +// Function Specification +// +// Name: proc_gpsm_dcm_sync_set_state +// +// Description: Set the state of global variable used for DCM sync +// Differnt nybble will get set depending on if we are +// DCM Master or DCM Slave +// +// End Function Specification +inline void proc_gpsm_dcm_sync_set_state(eProcGpsmDcmSyncStates i_dcm_sync_state) +{ + if(!gpsm_dcm_slave_p()) + { + G_proc_dcm_sync_state.sync_state_master = i_dcm_sync_state; + } + else + { + G_proc_dcm_sync_state.sync_state_slave = i_dcm_sync_state; + } +} + + +// Function Specification +// +// Name: proc_gpsm_dcm_sync_get_state +// +// Description: Return the state of global variable used for DCM sync +// +// End Function Specification +eProcGpsmDcmSyncStates proc_gpsm_dcm_sync_get_my_state(void) +{ + if(!gpsm_dcm_slave_p()) + { + return G_proc_dcm_sync_state.sync_state_master; + } + else + { + return G_proc_dcm_sync_state.sync_state_slave; + } +} + + +// Function Specification +// +// Name: proc_trace_pstate_table_quick +// +// Description: Debug Function to Print portion of Pstate Table +// Eventually, this should trace key elements of Pstate +// table to Trace Buffer. +// +// End Function Specification +void proc_trace_pstate_table_quick(void) +{ + GlobalPstateTable * l_gpst_ptr = NULL; + + l_gpst_ptr = gpsm_gpst(); + // Check the pointer since it may not have been installed on chips with 0 configured cores + if(l_gpst_ptr == &G_global_pstate_table) + { + TRAC_IMP("GPST Installed: Pstate[0]: %d kHz, Step: %d kHz, Entries: %d, Pvsafe[%d], Psafe[%d]", + l_gpst_ptr->pstate0_frequency_khz, + l_gpst_ptr->frequency_step_khz, + (int8_t) l_gpst_ptr->entries, + (int8_t) l_gpst_ptr->pvsafe, + (int8_t) l_gpst_ptr->psafe + ); + + TRAC_IMP("Pmin[%d]: %d kHz, Pmax[%d]: %d kHz", + (int8_t) l_gpst_ptr->pmin, + (l_gpst_ptr->pstate0_frequency_khz + ((int8_t) l_gpst_ptr->pmin) * l_gpst_ptr->frequency_step_khz), + ((int8_t) l_gpst_ptr->pmin + l_gpst_ptr->entries - 1), + (l_gpst_ptr->pstate0_frequency_khz + ((int8_t) l_gpst_ptr->pmin + l_gpst_ptr->entries - 1) * l_gpst_ptr->frequency_step_khz) + ); + } + else + { + //This likely means that the processor has no configured cores (may not be an error scenario) + TRAC_IMP("GPST not installed. hw pointer= 0x%08x, present cores= 0x%08x", (uint32_t)l_gpst_ptr, G_present_cores); + } +} + + +// Function Specification +// +// Name: proc_pstate2freq +// +// Description: Convert Pstate to Frequency +// +// End Function Specification +uint32_t proc_pstate2freq(Pstate i_pstate) +{ + uint32_t l_freq = 0; + int8_t l_pmax = 0; + GlobalPstateTable * l_gpst_ptr = NULL; + + do + { + // Get pointer to Pstate table + l_gpst_ptr = gpsm_gpst(); + + // Return the zero frequency if we don't have a PstateTable installed + if(&G_global_pstate_table != l_gpst_ptr) + { + l_freq = 0; + break; + } + + // Calculate Pmax, since it is derived instead of being a explicit member + l_pmax = ((int8_t) l_gpst_ptr->pmin + l_gpst_ptr->entries - 1); + + if(i_pstate < l_gpst_ptr->pmin) + { + // If passed in Pstate is lower than Pmin, just use Pmin + i_pstate = l_gpst_ptr->pmin; + } + else if (i_pstate > l_pmax) + { + // If passed in Pstate is greater than Pmax, just use Pmax + i_pstate = l_pmax; + } + + // Calculate Frequency based on Pstate + l_freq = (l_gpst_ptr->pstate0_frequency_khz + ((int8_t) i_pstate) * l_gpst_ptr->frequency_step_khz); + l_freq /= 1000; // Convert to MHz + } + while(0); + + return l_freq; // MHz +} + + +// Function Specification +// +// Name: proc_freq2pstate +// +// Description: Convert Frequency to Nearest Pstate +// +// End Function Specification +Pstate proc_freq2pstate(uint32_t i_freq_mhz) +{ + GlobalPstateTable * l_gpst_ptr = NULL; + int8_t l_pstate = PSTATE_MIN; + int8_t l_temp_pstate = 0; + int32_t l_temp_freq = 0; + uint32_t l_freq_khz = 0; + + do + { + // Get pointer to Pstate table + l_gpst_ptr = gpsm_gpst(); + + // Return the minimum PState if we don't have a PstateTable installed + if(&G_global_pstate_table != l_gpst_ptr) + { + break; + } + + // Freq Units need to be in kHz, not Mhz for the following calculations + l_freq_khz = i_freq_mhz * 1000; + + // Make sure that we don't ever get a frequency below the min Freq from + // def file + if(i_freq_mhz < G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY]) + { + l_freq_khz = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY] * 1000; + } + + if(l_freq_khz < G_proc_gpst_fmax) + { + // First, calculate the delta between passed in freq, and Pmin + l_temp_freq = l_freq_khz - G_proc_gpst_fmin; + + // Check if the passed in frequency is smaller than anything in the + // table + if(l_freq_khz <= G_proc_gpst_fmin) + { + // We need to substract a full step (minus 1) to make sure we + // are keeping things safe + l_temp_freq -= (l_gpst_ptr->frequency_step_khz - 1); + } + + // Next, calculate how many Pstate steps there are in that delta + l_temp_pstate = l_temp_freq / (int32_t)l_gpst_ptr->frequency_step_khz; + + // Lastly, calculate Pstate, by adding delta Pstate steps to Pmin + l_pstate = l_gpst_ptr->pmin + l_temp_pstate; + } + else + { + // Freq is bigger than anything in table -- return Pmax + l_pstate = G_proc_gpst_pmax; + } + } + while(0); + + return (Pstate) l_pstate; +} + + +// Function Specification +// +// Name: proc_gpsm_pstate_initialize +// +// Description: Initialize Pstate Table (and the rest of the Pstate +// SuperStructure). Also, initialize Global variables +// that will speed up the proc_freq2pstate function. +// +// End Function Specification +errlHndl_t proc_gpsm_pstate_initialize(const PstateSuperStructure* i_pss) +{ + errlHndl_t l_errlHndl = NULL; + GlobalPstateTable * l_gpst_ptr = NULL; + int l_rc = 0; + + do + { + /// Because early EC's of the Murano chip did not have valid #V data, + /// we need to exclude them from loading a pstate table created by a + /// hardware procedure. If we run a table created from a #V on these + /// chips, we could crash the box (or worse, burn something up!) + if ( (cfam_id() == CFAM_CHIP_ID_MURANO_10) + || (cfam_id() == CFAM_CHIP_ID_MURANO_11) ) + { + TRAC_ERR("OCC not supported on murano dd10 or dd11 due to bad #V data. chip id = 0x%08x"); + // Create Error Log and return to caller + /* @ + * @errortype + * @moduleid PROC_GPST_INIT_FAILURE_MOD + * @reasoncode INTERNAL_FAILURE + * @userdata1 chip id + * @userdata2 0 + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc OCC not supported on Murano DD10 or DD11 + */ + l_errlHndl = createErrl( + PROC_GPST_INIT_FAILURE_MOD, //modId + INTERNAL_FAILURE, //reasoncode + OCC_NO_EXTENDED_RC, //Extended reason code + ERRL_SEV_UNRECOVERABLE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + cfam_id(), //userdata1 + 0 //userdata2 + ); + + //callout the processor + addCalloutToErrl(l_errlHndl, + ERRL_CALLOUT_TYPE_HUID, + G_sysConfigData.proc_huid, + ERRL_CALLOUT_PRIORITY_HIGH); + break; + } + + l_rc = gpsm_initialize(i_pss, &G_global_pstate_table); + + // Print key elements of table for debug + proc_trace_pstate_table_quick(); + + // Get Pstate Table Ptr + l_gpst_ptr = gpsm_gpst(); + + if(l_rc || (l_gpst_ptr != &G_global_pstate_table)) + { + TRAC_ERR("gpsm_initialize failed with rc=0x%08x or l_gpstr_ptr=0x%08x", l_rc, l_gpst_ptr); + + // Create Error Log and return to caller + /* @ + * @errortype + * @moduleid PROC_GPST_INIT_FAILURE_MOD + * @reasoncode INTERNAL_FAILURE + * @userdata1 SRAM Address of the Pstate Table + * @userdata2 Return Code of call that failed + * @userdata4 ERC_PROC_PSTATE_INSTALL_FAILURE + * @devdesc Failed to install Pstate Table + */ + l_errlHndl = createErrl( + PROC_GPST_INIT_FAILURE_MOD, //modId + INTERNAL_FAILURE, //reasoncode + ERC_PROC_PSTATE_INSTALL_FAILURE, //Extended reason code + ERRL_SEV_UNRECOVERABLE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + (uint32_t) &G_global_pstate_table, //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); + break; + } + + + // set up key globals based on the pstate table. + + // Set the pstate state (state machine will start enabling pstates + // when it sees this) + proc_gpsm_dcm_sync_set_state(PROC_GPSM_SYNC_PSTATE_TABLE_INSTALLED); + + // Set up Key Globals for use by proc_freq2pstate functions + G_proc_gpst_fmax = l_gpst_ptr->pstate0_frequency_khz + + (((int8_t) l_gpst_ptr->pmin + l_gpst_ptr->entries - 1) + * l_gpst_ptr->frequency_step_khz); + G_proc_gpst_fmin = l_gpst_ptr->pstate0_frequency_khz + + (((int8_t) l_gpst_ptr->pmin) + * l_gpst_ptr->frequency_step_khz); + G_proc_gpst_pmax = l_gpst_ptr->pmin + l_gpst_ptr->entries - 1; + + // Dcom uses this to know whether to pass DCM msgs or not. + G_isDcm = gpsm_dcm_mode_p(); + + // Set globals used by amec for pcap calculation + G_mhz_per_pstate = (l_gpst_ptr->frequency_step_khz)/1000; + + }while(0); + + return l_errlHndl; +} + + +// 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: 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: populate_pstate_to_sapphire_tbl +// +// Description: +// +// End Function Specification +void populate_pstate_to_sapphire_tbl() +{ + uint8_t i = 0; + GlobalPstateTable * l_gpst_ptr = NULL; + + memset(&G_sapphire_table, 0, sizeof(sapphire_table_t)); + + l_gpst_ptr = gpsm_gpst(); + const int8_t l_pmax = (int8_t) l_gpst_ptr->pmin + l_gpst_ptr->entries - 1; + G_sapphire_table.config.valid = 1; // default 0x01 + G_sapphire_table.config.version = 1; // default 0x01 + G_sapphire_table.config.throttle = NO_THROTTLE; // default 0x00 + G_sapphire_table.config.pmin = gpst_pmin(&G_global_pstate_table)+1; //Per David Du, we must use pmin+1 to avoid gpsa hang + G_sapphire_table.config.pnominal = (int8_t)proc_freq2pstate(G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL]); + G_sapphire_table.config.pmax = gpst_pmax(&G_global_pstate_table); + const uint16_t l_entries = G_sapphire_table.config.pmax - G_sapphire_table.config.pmin + 1; + const uint8_t l_idx = l_gpst_ptr->entries-1; + + for (i = 0; i < l_entries; i++) + { + G_sapphire_table.data[i].pstate = (int8_t) l_pmax - i; + G_sapphire_table.data[i].flag = 0; // default 0x00 + if (i < l_gpst_ptr->entries) + { + G_sapphire_table.data[i].evid_vdd = l_gpst_ptr->pstate[i].fields.evid_vdd; + G_sapphire_table.data[i].evid_vcs = l_gpst_ptr->pstate[i].fields.evid_vcs; + } + else + { + // leave the VDD & VCS Vids the same as the "Pstate Table Pmin" + G_sapphire_table.data[i].evid_vdd = l_gpst_ptr->pstate[l_idx].fields.evid_vdd; + G_sapphire_table.data[i].evid_vcs = l_gpst_ptr->pstate[l_idx].fields.evid_vcs; + } + // extrapolate the frequency + G_sapphire_table.data[i].freq_khz = l_gpst_ptr->pstate0_frequency_khz + (G_sapphire_table.data[i].pstate * l_gpst_ptr->frequency_step_khz); + } +} + +// Function Specification +// +// Name: populate_sapphire_tbl_to_mem +// +// Description: +// +// End Function Specification +void populate_sapphire_tbl_to_mem() +{ + int l_ssxrc = SSX_OK; + uint32_t l_reasonCode = 0; + uint32_t l_extReasonCode = 0; + + do + { +#define SAPPHIRE_OFFSET_IN_HOMER 0x001F8000 + BceRequest pba_copy; + // Set up copy request + l_ssxrc = bce_request_create(&pba_copy, // block copy object + &G_pba_bcue_queue, // sram to mainstore copy engine + SAPPHIRE_OFFSET_IN_HOMER, // mainstore address + (uint32_t) &G_sapphire_table, // sram starting address + (size_t) sizeof(G_sapphire_table), // size of copy + SSX_WAIT_FOREVER, // no timeout + NULL, // call back + NULL, // call back arguments + ASYNC_REQUEST_BLOCKING // callback mask + ); + + if(l_ssxrc != SSX_OK) + { + TRAC_ERR("populate_sapphire_tbl_to_mem: PBA request create failure rc=[%08X]", -l_ssxrc); + /* + * @errortype + * @moduleid MAIN_STATE_TRANSITION_MID + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 RC for PBA block-copy engine + * @userdata4 ERC_BCE_REQUEST_CREATE_FAILURE + * @devdesc SSX BCE related failure + */ + l_reasonCode = SSX_GENERIC_FAILURE; + l_extReasonCode = ERC_BCE_REQUEST_CREATE_FAILURE; + break; + } + + // Do actual copying + l_ssxrc = bce_request_schedule(&pba_copy); + + if(l_ssxrc != SSX_OK) + { + TRAC_ERR("populate_sapphire_tbl_to_mem: PBA request schedule failure rc=[%08X]", -l_ssxrc); + /* + * @errortype + * @moduleid MAIN_STATE_TRANSITION_MID + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 RC for PBA block-copy engine + * @userdata4 ERC_BCE_REQUEST_SCHEDULE_FAILURE + * @devdesc Failed to copy data by using DMA + */ + l_reasonCode = SSX_GENERIC_FAILURE; + l_extReasonCode = ERC_BCE_REQUEST_SCHEDULE_FAILURE; + break; + } + } while(0); + + if ( l_ssxrc != SSX_OK ) + { + errlHndl_t l_errl = createErrl(MAIN_STATE_TRANSITION_MID, //modId + l_reasonCode, //reasoncode + l_extReasonCode, //Extended reason code + ERRL_SEV_UNRECOVERABLE, //Severity + NULL, //Trace Buf + 0, //Trace Size + -l_ssxrc, //userdata1 + 0); //userdata2 + + // Callout firmware + addCalloutToErrl(l_errl, + ERRL_CALLOUT_TYPE_COMPONENT_ID, + ERRL_COMPONENT_ID_FIRMWARE, + ERRL_CALLOUT_PRIORITY_HIGH); + + commitErrl(&l_errl); + } +} + +// Function Specification +// +// Name: proc_check_for_sapphire_updates +// +// Description: Checks if the sapphire table needs an update +// and updates if necessary. +// +// End Function Specification +void proc_check_for_sapphire_updates() +{ + uint8_t l_latest_throttle_reason; + + //If safe state is requested then that overrides anything from amec + if(isSafeStateRequested()) + { + l_latest_throttle_reason = OCC_RESET; + } + else + { + l_latest_throttle_reason = G_amec_kvm_throt_reason; + } + + //If the throttle reason changed, update it in the HOMER + if(G_sapphire_table.config.throttle != l_latest_throttle_reason) + { + TRAC_INFO("proc_check_for_sapphire_updates: throttle reason changed to %d", l_latest_throttle_reason); + G_sapphire_table.config.throttle = l_latest_throttle_reason; + G_sapphire_table.config.version = 1; // default 0x01 + G_sapphire_table.config.valid = 1; //default 0x01 + populate_sapphire_tbl_to_mem(); + } +} diff --git a/src/occ_405/proc/proc_pstate.h b/src/occ_405/proc/proc_pstate.h new file mode 100755 index 0000000..3ac8439 --- /dev/null +++ b/src/occ_405/proc/proc_pstate.h @@ -0,0 +1,131 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/proc/proc_pstate.h $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* [+] 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 */ + +#ifndef PROC_PSTATE_H +#define PROC_PSTATE_H + +#include "ssx.h" +#include "cmdh_service_codes.h" +#include "errl.h" +#include "trac.h" +#include "rtls.h" +#include "occ_common.h" +#include "state.h" +#include "cmdh_fsp_cmds.h" +#include "cmdhDbugCmd.h" +#include "appletManager.h" +#include "gpsm.h" +#include "pstates.h" + +// GPSM DCM Synchronization - used by MBOX to transfer between DCM M & S +typedef struct +{ + uint8_t dcm_pair_id; + uint8_t sync_state_master :4; + uint8_t sync_state_slave :4; + uint8_t pstate_v; + uint8_t pstate_f; +} proc_gpsm_dcm_sync_occfw_t; + +typedef struct __attribute__ ((packed)) +{ + uint8_t valid; + uint8_t version; + // Sapphire_OCC_interface_v3.odp + // throttle status 0x00 No throttle, 0x01 Powercap, 0x02 CPU overtemp, 0x03 power supply failure, 0x04 overcurrent, 0x05 OCC reset + uint8_t throttle; + int8_t pmin; + int8_t pnominal; + int8_t pmax; + uint16_t spare; +} sapphire_config_t; + +typedef struct __attribute__ ((packed)) +{ + int8_t pstate; + uint8_t flag; + uint8_t evid_vdd; + uint8_t evid_vcs; + uint32_t freq_khz; +} sapphire_data_t; + +#define PSTATE_ENTRY_NUMBER 256 +// This size must be a multiple of 128 +typedef struct __attribute__ ((packed)) +{ + sapphire_config_t config; + uint64_t reserved; + sapphire_data_t data[PSTATE_ENTRY_NUMBER]; + uint8_t pad[112]; +} sapphire_table_t __attribute__ ((aligned (128))); + +enum { + NO_THROTTLE = 0x00, + POWERCAP = 0x01, + CPU_OVERTEMP = 0x02, + POWER_SUPPLY_FAILURE = 0x03, + OVERCURRENT = 0x04, + OCC_RESET = 0x05, +}; + +extern GlobalPstateTable G_global_pstate_table; + +extern uint32_t G_mhz_per_pstate; + +extern sapphire_table_t G_sapphire_table; + +// Initialize PState Table +errlHndl_t proc_gpsm_pstate_initialize(const PstateSuperStructure* i_pss); + +// Entry function for enabling Pstates once table is installed +void proc_gpsm_dcm_sync_enable_pstates_smh(void); + +// Get DCM Sync State +proc_gpsm_dcm_sync_occfw_t proc_gpsm_dcm_sync_get_state(void); + +// Pull down DCM pair's Sync State & Info via Mbox +void proc_gpsm_dcm_sync_update_from_mbox(proc_gpsm_dcm_sync_occfw_t * i_dcm_sync_state); + +// Helper function to translate from Frequency to nearest Pstate +Pstate proc_freq2pstate(uint32_t i_freq_mhz); + +// Helper function to translate from Pstate to nearest Frequency +uint32_t proc_pstate2freq(Pstate i_pstate); + +// Helper function to determine if we are a DCM +inline bool proc_is_dcm(); + +// Helper function to determine if we are in HW Pstate mode +inline bool proc_is_hwpstate_enabled(void); + +// Copy pstate data to sapphire table +void populate_pstate_to_sapphire_tbl(); + +// Copy sapphire table to mainstore memory at SAPPHIRE_OFFSET_IN_HOMER +void populate_sapphire_tbl_to_mem(); + +// Check if sapphire table needs update +void proc_check_for_sapphire_updates(); +#endif diff --git a/src/occ_405/proc/test/Makefile b/src/occ_405/proc/test/Makefile new file mode 100755 index 0000000..5360629 --- /dev/null +++ b/src/occ_405/proc/test/Makefile @@ -0,0 +1,89 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/occ_405/proc/test/Makefile $ +# +# OpenPOWER OnChipController Project +# +# Contributors Listed Below - COPYRIGHT 2011,2015 +# [+] 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 + + +proctest_CFILES = \ + ../../common.c \ + ../../errl/errl.c \ + ../../pss/apss.c \ + ../../rtls/rtls.c \ + ../../thread/threadSch.c \ + ../../aplt/appletManager.c \ + ../proc_data.c \ + ../../rtls/rtls_tables.c \ + ../../timer/timer.c \ + ../../dcom/dcom.c \ + ../../occ_sys_config.c \ + main.c +all_cfiles = ${proctest_CFILES} + +occ_GPEFILES = ../../gpe/apss_init.S \ + ../../gpe/apss_composite.S \ + ../../gpe/apss_meas_read_start.S \ + ../../gpe/apss_meas_read_cont.S \ + ../../gpe/apss_meas_read_complete.S \ + ../../gpe/pore_test.S +all_gpefiles = ${occ_GPEFILES} + +APP = proctest +APP_INCLUDES += -I../../../ssx +APP_INCLUDES += -I../../../lib +APP_INCLUDES += -I../../incl +APP_INCLUDES += -I../../trac +APP_INCLUDES += -I../../errl +APP_INCLUDES += -I../../thread +APP_INCLUDES += -I../../gpe +APP_INCLUDES += -I../../aplt +APP_INCLUDES += -I../../aplt/incl +APP_INCLUDES += -I../../sensor +APP_INCLUDES += -I../../pss +APP_INCLUDES += -I../../rtls +APP_INCLUDES += -I../../async +APP_INCLUDES += -I../../proc +APP_INCLUDES += -I../../timer +APP_INCLUDES += -I../../dcom +APP_INCLUDES += -I. + +D = -DOCC_FIRMWARE=1 + +#D = -DVERIFICATION=1 \ + -DSSX_STACK_CHECK=0 \ + -DINITIALIZE_PMC=0 \ + -DINITIALIZE_SIMICS_IO=0 \ + -DINITIALIZE_RTX_IO=1 \ + -DINITIALIZE_PBA=1 \ + -DSIMICS_MAGIC_PANIC=1 \ + -DSSX_KERNEL_TRACE_ENABLE=1 + + +SOURCES = ${all_cfiles} ${all_gpefiles} +MODE = validation + +PGP_ASYNC_SUPPORT = 1 + +include ./app.mk + +pgas: + $(CC) $(CFLAGS) -c -Wa,-al -Wa,--listing-cont-lines='10' ${all_gpefiles} diff --git a/src/occ_405/proc/test/app.mk b/src/occ_405/proc/test/app.mk new file mode 100755 index 0000000..754609a --- /dev/null +++ b/src/occ_405/proc/test/app.mk @@ -0,0 +1,104 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/occ_405/proc/test/app.mk $ +# +# OpenPOWER OnChipController Project +# +# Contributors Listed Below - COPYRIGHT 2011,2015 +# [+] 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 + +# Description: mk occ application +# +# This Makefile is included-ed into application Makefiles and +# encapsulates the steps necessary to create application images. +# +# The application Makefile (user) must define the following variables: +# +# APP - The name of the application +# SOURCES - The list of local source files that implement the +# application. +# +# The application Makefile (user) may optionally define the following +# variables: +# +# D - The value of $(D) is appended to DEFS defined by ssx.mk +# +# MODE - The following modes are recognized: +# +# validation - (Default) An application that requires all SSX +# services. +# +# firmware - An interrupt only configuration. +# +# The make process creates the following files: +# +# $(APP).out - The PowerPC-ELF version of the application +# $(APP).bin - A binary SRAM image of the application +# $(APP).map - The linker map of the application + +OCC = ../../ +SSX = ../../../ssx +LIB = ../../../lib +PGP = $(SSX)/pgp + +ifeq "$(MODE)" "firmware" +SSX_TIMER_SUPPORT = 0 +SSX_THREAD_SUPPORT = 0 +endif + +export SSX_TIMER_SUPPORT +export SSX_THREAD_SUPPORT +export PPC405_MMU_SUPPORT +export PGP_ASYNC_SUPPORT + +INCLUDES = -I $(OCC) -I$(LIB) + +include $(PGP)/ssx.mk + +C-OBJECTS = $(SOURCES:.c=.o) +OBJECTS = $(C-OBJECTS:.S=.o) + +LDFLAGS = -L $(SSX)/ssx -L $(SSX)/ppc32 -L $(SSX)/ppc405 -L $(SSX)/pgp \ + -L $(OCC) -L $(LIB) -lssx -lppc32 + +DEFS += $(D) + +all: $(OBJECTS) libssx.a + $(MAKE) -C $(PGP) DEFS="$(DEFS)" -e + $(CPP) -P $(DEFS) < $(OCC)/linkocc.cmd > linkscript + $(LD) $(OBJECTS) \ + -Tlinkscript $(LDFLAGS) -Map $(APP).map -Bstatic -o $(APP).out + $(OBJCOPY) -O binary $(APP).out $(APP).bin + $(OBJDUMP) -d $(APP).out > $(APP).dis + +libssx.a: + $(MAKE) -C $(LIB) DEFS="$(DEFS)" -e + + +.PHONY : clean +clean: + rm -f *.o *.d *.d.* *.out *.bin *.srec *.dis *.map linkscript + rm -f ./*/*.o ./*/*.d ./*/*.d.* + +.PHONY : clean_all +clean_all: + $(MAKE) clean + $(MAKE) -C $(PGP) clean + +-include $(OBJECTS:.o=.d) diff --git a/src/occ_405/proc/test/main.c b/src/occ_405/proc/test/main.c new file mode 100755 index 0000000..314d87d --- /dev/null +++ b/src/occ_405/proc/test/main.c @@ -0,0 +1,352 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/proc/test/main.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* [+] 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 "ssx.h" +#include "ssx_io.h" +#include "simics_stdio.h" +#include <thread.h> +#include <threadSch.h> +#include <errl.h> +#include <apss.h> +#include <appletManager.h> +#include <trac.h> +#include <occ_service_codes.h> +#include <occ_sys_config.h> +#include <proc_data.h> +#include <timer.h> +#include <dcom.h> +#include <rtls.h> + +extern void __ssx_boot; + +IMAGE_HEADER (G_mainAppImageHdr,__ssx_boot,MAIN_APP_ID,OCC_APLT_TEST); + +// Period in which to run #timer_routine +#define TIMER_INTERVAL (SsxInterval) SSX_MICROSECONDS(5000) + +int g_j = 0; +int g_k = 0; + +SimicsStdio simics_stdout; +SimicsStdio simics_stderr; + +uint8_t noncritical_stack[NONCRITICAL_STACK_SIZE]; +uint8_t critical_stack[CRITICAL_STACK_SIZE]; + +// Function Specification +// +// Name: pgp_validation_ssx_main_hook +// +// Description: +// +// End Function Specification +void pgp_validation_ssx_main_hook(void) +{ + +} + +// Function Specification +// +// Name: Cmd_Hndl_thread_routine +// +// Description: +// +// End Function Specification +void Cmd_Hndl_thread_routine(void *arg) +{ + TRAC_INFO("Command Handler Thread Started ... " ); +} + +// Function Specification +// +// Name: Thermal_Monitor_thread_routine +// +// Description: +// +// End Function Specification +void Thermal_Monitor_thread_routine(void *arg) +{ + TRAC_INFO("Thermal Monitor Thread Started ... " ); +} + +// Function Specification +// +// Name: Hlth_Monitor_thread_routine +// +// Description: +// +// End Function Specification +void Hlth_Monitor_thread_routine(void *arg) +{ + TRAC_INFO("Health Monitor Thread Started ... " ); +} + +// Function Specification +// +// Name: FFDC_thread_routine +// +// Description: +// +// End Function Specification +void FFDC_thread_routine(void *arg) +{ + TRAC_INFO("FFDC Thread Started ... " ); +} + +// Function Specification +// +// Name: get_core_info +// +// Description: +// +// End Function Specification +void get_core_info() +{ + //uintt64_t l_deconfigured_cores; + uint32_t l_deconfigured_cores; + uint32_t l_configured_cores; + + //rc = _getscom( PMC_CORE_DECONFIGURATION_REG, &l_deconfigured_cores, SCOM_TIMEOUT ); + + l_deconfigured_cores = in32(PMC_CORE_DECONFIGURATION_REG); + PROC_DEBUG( "Deconfigured cores in the chip [0x%x]\n", l_deconfigured_cores); + + + l_configured_cores = ~l_deconfigured_cores & ALL_CORES_MASK; + PROC_DEBUG( "Configured cores in the chip [0x%x]\n", l_configured_cores); + + return; +} + +// Function Specification +// +// Name: main_thread_routine +// +// Description: This thread currently just loops as the lowest priority thread, handling +// the lowest priority tasks. +// +// End Function Specification +void main_thread_routine(void *private) +{ + + TRAC_INFO("Main Thread Started ... " ); + errlHndl_t l_errl = NULL; + SsxSemaphore l_appletComplete; + uint8_t l_status = 0; + uint32_t l_rc = 0 ; + int l_ssxrc = 0; + + // Start the critical 250uS timer + //ssx_timer_schedule(&timer, 1, TIMER_INTERVAL); + + // Initialize applet semaphore + l_ssxrc = ssx_semaphore_create(&l_appletComplete, 0, 1); + + // Initialize APSS +#ifdef OCC_ALONE_SIMICS + l_rc = runApplet(OCC_APLT_APSS_INIT, // Applet enum Name + NULL, // Applet arguments + TRUE, // Blocking call? + &l_appletComplete, // Applet finished semaphore + &l_errl, // error log handle + &l_status); // status from applet manager +#endif + if( NULL != l_errl ) + { + TRAC_ERR("APSS Init failed! (retrying) ErrLog[%p]", l_errl ); + setErrlSevToInfo(l_errl); + // commit & delete + commitErrl( &l_errl ); + + l_rc = runApplet(OCC_APLT_APSS_INIT, // Applet enum Name + NULL, // Applet arguments + TRUE, // Blocking call? + &l_appletComplete, // Applet finished semaphore + &l_errl, // error log handle + &l_status); // status from applet manager + if( NULL != l_errl ) + { + TRAC_ERR("APSS Init failed again! (OCC will be reset)ErrLog[%p]", + l_errl ); + + // commit & delete + commitErrl( &l_errl ); + + //$TODO: Request OCC Reset + } + } + + while(1) + { + // Only trace the first XX times that this function loops + if(g_k < 3) + { + g_k++; + + } + + // Sleep for 1000 before we run the loop again + ssx_sleep(SSX_SECONDS(5)); + } +} + + +// Function Specification +// +// Name: main +// +// Description: Entry point for OCC execution +// Currently initalizes our trace buffer along with creating threads +// and timers for execution. Note that once main runs ssx_start_threads, +// we never return as the SSX kernel takes over. +// +// End Function Specification +int main(int argc, char **argv) +{ + // Initialize stdout so we can do printf from within simics env + simics_stdout_create(&simics_stdout); + simics_stderr_create(&simics_stderr); + stdout = (FILE *)(&simics_stdout); + stderr = (FILE *)(&simics_stderr); + ssxout = (FILE *)(&simics_stdout); + + TRAC_INFO("Inside OCC Main"); + + // Initialize SSX Stacks (note that this also reinitializes the time base to 0) + ssx_initialize((SsxAddress)noncritical_stack, NONCRITICAL_STACK_SIZE, + (SsxAddress)critical_stack, CRITICAL_STACK_SIZE, + 0); + + // Create Threads + ssx_thread_create(&main_thread, + main_thread_routine, + (void *)0, + (SsxAddress)main_thread_stack, + THREAD_STACK_SIZE, + 1); + + + // Make Threads runnable + ssx_thread_resume(&main_thread); + + errlHndl_t l_errl = NULL; + //Initialize the thread scheduler + l_errl = initThreadScheduler(); + + if( l_errl ) + { + // Trace and commit error + TRAC_ERR("init thread Scheduler failure"); + + // commit log + // NOTE: log should be deleted by reader mechanism + commitErrl( &l_errl ); + } + + // lets map mainstore to oci space only once + // NOTE: This will stay mapped for remainder of occ life + // TODO: This sounds like a temporary solution and may + // end up moving to simics environment setup + // TODO: This map needs to be unmapped after done accessing + // main memory for the OCC initialization. + Ppc405MmuMap pba_mmu_map; + int l_ssxrc1 = ppc405_mmu_map( + 0, //Mainstore address 0x0 + 0, //OCI address 0x0 + 1048576, //Max size = 1 Mb + 0, // + 0, //no TLBIE permissions only need to read + &pba_mmu_map + ); + + if ( l_ssxrc1 != SSX_OK ) + { + tracDesc_t l_trace = NULL; + + TRAC_ERR("mmu map failure SsxRc[0x%08X]", -l_ssxrc1 ); + + /* + * @errortype + * @moduleid MAIN_MID + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 pore_flex_schedule return code + * @userdata4 ERC_MMU_MAP_FAILURE + * @devdesc Failure mapping OCI space + */ + l_errl = createErrl( + MAIN_MID, //modId + SSX_GENERIC_FAILURE, //reasoncode + ERC_MMU_MAP_FAILURE, //Extended reason code + ERRL_SEV_UNRECOVERABLE, //Severity + l_trace, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + l_ssxrc1, //userdata1 + 0 //userdata2 + ); + + // Callout firmware + addCalloutToErrl(l_errl, + ERRL_CALLOUT_TYPE_COMPONENT_ID, + ERRL_COMPONENT_ID_FIRMWARE, + ERRL_CALLOUT_PRIORITY_HIGH); + + // commit log + commitErrl( &l_errl ); + + // TODO request a reset of OCC since applet manager will + // be toast without this working correctly + } + + //Initialize the Applet Manager + l_errl = initAppletManager(); + + if( l_errl ) + { + // Trace and commit error + TRAC_ERR("init Applet Manager failure"); + + // commit log + commitErrl( &l_errl ); + + // TODO: request a reset of OCC since applet manager will + // be toast without this working correctly + } + + //Initialize structures for collecting core data. + //It needs to run before RTLoop start. + proc_core_init(); + + get_core_info(); + + // Initialize Realtime Loop Timer Interrupt + rtl_ocb_init(); + + // Enter SSX Kernel + ssx_start_threads(); + + return 0; +} + |