summaryrefslogtreecommitdiffstats
path: root/src/occ_405/proc
diff options
context:
space:
mode:
authorWilliam Bryan <wilbryan@us.ibm.com>2015-08-03 12:38:58 -0500
committerWilliam A. Bryan <wilbryan@us.ibm.com>2015-08-03 15:32:27 -0500
commit420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3 (patch)
treec9f6691eddba39193e39aa769367e1267fb9fc86 /src/occ_405/proc
parentadade8c8ef30ed519322674c762d95663009c5d4 (diff)
downloadtalos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.tar.gz
talos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.zip
new ssx and lib files
Change-Id: I2328b1e86d59e3788910687d762fb70ec680058f Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/19503 Reviewed-by: William A. Bryan <wilbryan@us.ibm.com> Tested-by: William A. Bryan <wilbryan@us.ibm.com>
Diffstat (limited to 'src/occ_405/proc')
-rwxr-xr-xsrc/occ_405/proc/proc_data.c837
-rwxr-xr-xsrc/occ_405/proc/proc_data.h179
-rwxr-xr-xsrc/occ_405/proc/proc_data_control.c264
-rwxr-xr-xsrc/occ_405/proc/proc_data_control.h48
-rwxr-xr-xsrc/occ_405/proc/proc_data_service_codes.h41
-rwxr-xr-xsrc/occ_405/proc/proc_pstate.c1080
-rwxr-xr-xsrc/occ_405/proc/proc_pstate.h131
-rwxr-xr-xsrc/occ_405/proc/test/Makefile89
-rwxr-xr-xsrc/occ_405/proc/test/app.mk104
-rwxr-xr-xsrc/occ_405/proc/test/main.c352
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;
+}
+
OpenPOWER on IntegriCloud