summaryrefslogtreecommitdiffstats
path: root/src/occ_405/amec
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/amec
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/amec')
-rwxr-xr-xsrc/occ_405/amec/amec_amester.c1564
-rw-r--r--src/occ_405/amec/amec_amester.h327
-rwxr-xr-xsrc/occ_405/amec/amec_analytics.c536
-rwxr-xr-xsrc/occ_405/amec/amec_analytics.h47
-rw-r--r--src/occ_405/amec/amec_controller.c438
-rw-r--r--src/occ_405/amec/amec_controller.h132
-rwxr-xr-xsrc/occ_405/amec/amec_data.c477
-rwxr-xr-xsrc/occ_405/amec/amec_data.h82
-rwxr-xr-xsrc/occ_405/amec/amec_dps.c365
-rwxr-xr-xsrc/occ_405/amec/amec_dps.h114
-rwxr-xr-xsrc/occ_405/amec/amec_external.h69
-rwxr-xr-xsrc/occ_405/amec/amec_freq.c1069
-rw-r--r--src/occ_405/amec/amec_freq.h170
-rwxr-xr-xsrc/occ_405/amec/amec_health.c1034
-rwxr-xr-xsrc/occ_405/amec/amec_health.h52
-rw-r--r--src/occ_405/amec/amec_init.c436
-rwxr-xr-xsrc/occ_405/amec/amec_master_smh.c1076
-rwxr-xr-xsrc/occ_405/amec/amec_master_smh.h162
-rwxr-xr-xsrc/occ_405/amec/amec_oversub.c252
-rwxr-xr-xsrc/occ_405/amec/amec_oversub.h117
-rwxr-xr-xsrc/occ_405/amec/amec_parm.c306
-rwxr-xr-xsrc/occ_405/amec/amec_parm.h181
-rwxr-xr-xsrc/occ_405/amec/amec_parm_table.c168
-rwxr-xr-xsrc/occ_405/amec/amec_part.c468
-rwxr-xr-xsrc/occ_405/amec/amec_part.h151
-rwxr-xr-xsrc/occ_405/amec/amec_pcap.c538
-rwxr-xr-xsrc/occ_405/amec/amec_pcap.h80
-rwxr-xr-xsrc/occ_405/amec/amec_perfcount.c134
-rwxr-xr-xsrc/occ_405/amec/amec_perfcount.h89
-rw-r--r--src/occ_405/amec/amec_sensors_centaur.c686
-rw-r--r--src/occ_405/amec/amec_sensors_centaur.h36
-rwxr-xr-xsrc/occ_405/amec/amec_sensors_core.c882
-rwxr-xr-xsrc/occ_405/amec/amec_sensors_core.h60
-rw-r--r--src/occ_405/amec/amec_sensors_fw.c242
-rwxr-xr-xsrc/occ_405/amec/amec_sensors_fw.h53
-rwxr-xr-xsrc/occ_405/amec/amec_sensors_power.c668
-rwxr-xr-xsrc/occ_405/amec/amec_sensors_power.h61
-rwxr-xr-xsrc/occ_405/amec/amec_service_codes.h73
-rwxr-xr-xsrc/occ_405/amec/amec_slave_smh.c768
-rwxr-xr-xsrc/occ_405/amec/amec_slave_smh.h110
-rwxr-xr-xsrc/occ_405/amec/amec_smh.h100
-rwxr-xr-xsrc/occ_405/amec/amec_sys.h729
-rwxr-xr-xsrc/occ_405/amec/amec_tasks.c292
43 files changed, 15394 insertions, 0 deletions
diff --git a/src/occ_405/amec/amec_amester.c b/src/occ_405/amec/amec_amester.c
new file mode 100755
index 0000000..c565912
--- /dev/null
+++ b/src/occ_405/amec/amec_amester.c
@@ -0,0 +1,1564 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_amester.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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include <errl.h> // Error logging
+#include <rtls.h>
+#include <occ_service_codes.h> // for SSX_GENERIC_FAILURE
+#include <sensor.h>
+#include <amec_smh.h>
+#include <amec_master_smh.h>
+#include <amec_amester.h>
+#include <amec_sys.h>
+#include <trac.h> // For traces
+#include <appletManager.h>
+#include <sensorQueryList.h>
+#include <proc_data.h>
+#include <amec_parm.h>
+#include <string.h>
+#include <occ_sys_config.h>
+#include <dcom.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+///Maximum size of trace buffer
+#define AMEC_TB_2MS_SIZE_BYTES 8192
+#define AMEC_TB_250US_SIZE_BYTES 8192
+#define AMEC_TB_SIZE_BYTES (AMEC_TB_250US_SIZE_BYTES + AMEC_TB_2MS_SIZE_BYTES)
+
+///Maximum number of trace buffers we will support
+#define AMEC_MAX_NUM_TB 2
+
+///Maximum size of config info for 1 trace buffer
+#define AMEC_TB_CONFIG_SIZE (MAX_SENSOR_NAME_SZ + 4)
+#define MAX_NUM_CHIPS MAX_NUM_OCC
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+// Each trace buffer should be aligned to 128 bytes in main memory because the
+// block copy engine only copies multiples of 128 byte units.
+// Make this a power of 2 (bytes) in size and aligned to 4 bytes.
+DMA_BUFFER(UINT8 g_amec_tb_bytes[AMEC_TB_SIZE_BYTES]);
+
+// Array that maintains a list of all trace buffers built.
+// NOTE: Must be in same order as AMEC_TB_ENUM
+DMA_BUFFER(amec_tb_t g_amec_tb_list[AMEC_MAX_NUM_TB]) = {
+ //trace 2ms
+ [AMEC_TB_2MS] = {
+ "trace2ms", // name
+ AMEFP(500,0), // freq
+ (UINT8*)(UINT32)g_amec_tb_bytes, // bytes
+ AMEC_TB_2MS_SIZE_BYTES, // size
+ 0, // entry_size
+ 0, // entry_n
+ 0, // write
+ 0, // read
+ 0, // sensors_n
+ 0, // parm_n
+ {0}, // sensors_field[]
+ {0}, // sensors_num[]
+ {0} // parms_num[]
+ },
+ // trace 250us
+ [AMEC_TB_250US] = {
+ "trace250us", // name
+ AMEFP(4000,0), // freq
+ (UINT8*)(UINT32)g_amec_tb_bytes+AMEC_TB_2MS_SIZE_BYTES, // bytes
+ AMEC_TB_250US_SIZE_BYTES, //size
+ 0, // entry_size
+ 0, // entry_n
+ 0, // write
+ 0, // read
+ 0, // sensors_n
+ 0, // parm_n
+ {0}, // sensors_field[]
+ {0}, // sensors_num[]
+ {0} // parms_num[]
+ }
+};
+
+//Throw a compiler error when the enum and array are not both updated
+STATIC_ASSERT((AMEC_TB_NUMBER_OF_TRACES != (sizeof(g_amec_tb_list)/sizeof(amec_tb_t))));
+
+///=1 signals a trace is being taken
+UINT8 g_amec_tb_record=0;
+///=1 signals continuous tracing
+UINT8 g_amec_tb_continuous=0; //CL273
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+// Function Specification
+//
+// Name: amester_get_sensor_info
+//
+// Description: Returns name, units, update frequency, and scalefactor for a sensor
+//
+// Task Flags:
+//
+// End Function Specification
+static uint8_t amester_get_sensor_info( uint8_t* o_resp, uint16_t* io_resp_length, const uint8_t i_type, const uint16_t i_sensor)
+{
+ uint8_t l_rc = COMPCODE_NORMAL; // assume no error
+ sensor_t * l_sensor_ptr = NULL;
+ uint16_t l_numOfSensors = 1;
+ sensor_info_t l_sensorInfo;
+ errlHndl_t l_err = NULL;
+ OCC_APLT_STATUS_CODES l_status = 0;
+ uint16_t l_resp_length = 0;
+
+ do
+ {
+ // Check o_resp and io_resp_length pointers
+ if( (o_resp == NULL) ||
+ (io_resp_length == NULL) )
+ {
+ l_rc = COMPCODE_UNSPECIFIED;
+ break;
+ }
+
+ l_resp_length = *io_resp_length;
+ *io_resp_length = 0;
+
+ if (i_sensor >= MAX_AMEC_SENSORS )
+ {
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ l_sensor_ptr = getSensorByGsid(i_sensor);
+ if(l_sensor_ptr == NULL)
+ {
+ // Didn't find it
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ querySensorListAppletArg_t l_querySensorListAppletArg = {
+ i_sensor, // i_startGsid
+ 0, // i_present
+ SENSOR_TYPE_ALL, // i_type
+ SENSOR_LOC_ALL, // i_loc
+ &l_numOfSensors, // io_numOfSensors
+ NULL, // o_sensors
+ &l_sensorInfo // o_sensorInfoPtr
+ };
+
+
+ //Call sensor query list applet
+ runApplet(OCC_APLT_SNSR_QUERY, // Applet enum Name
+ &l_querySensorListAppletArg, // Applet arguments
+ TRUE, // Blocking call?
+ NULL, // Applet finished semaphore
+ &l_err, // Error log handle
+ &l_status); // Error status
+
+ if( NULL != l_err)
+ {
+ // Query failure, it should not happens
+ TRAC_ERR("Failed to run OCC_APLT_SNSR_QUERY applet. Error status is : 0x%x", l_status);
+
+ // commit error log
+ commitErrl( &l_err );
+
+ l_rc = COMPCODE_UNSPECIFIED;
+ break;
+ }
+
+ switch (i_type)
+ {
+ case AME_INFO_NAME:
+ {
+ char *src = l_sensorInfo.name;
+ char *dest = (char*)o_resp;
+ uint16_t l_length = strlen(src)+1; // add string terminator
+
+ // Check length
+ if(l_resp_length < l_length)
+ {
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+ // Copy string
+ strcpy( dest, src );
+ *io_resp_length = l_length;
+ break;
+ }
+
+ case AME_INFO_UNITS:
+ {
+ char *src = l_sensorInfo.sensor.units;
+ char *dest = (char*)o_resp;
+ uint16_t l_length = strlen(src)+1; // add string terminator
+
+ // Check length
+ if(l_resp_length < l_length)
+ {
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ // Copy string
+ strcpy( dest, src );
+ *io_resp_length = l_length;
+ break;
+ }
+
+ case AME_INFO_FREQ:
+ {
+ uint16_t l_length = sizeof( uint32_t);
+
+ // Check length
+ if(l_resp_length < l_length)
+ {
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ *((uint32_t *)o_resp) = l_sensorInfo.sensor.freq;
+ *io_resp_length = l_length;
+ break;
+ }
+
+ case AME_INFO_SCALE:
+ {
+ uint16_t l_length = sizeof( uint32_t);
+
+ // Check length
+ if(l_resp_length < l_length)
+ {
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ *((uint32_t *)o_resp) = l_sensorInfo.sensor.scalefactor;
+ *io_resp_length = l_length;
+ break;
+ }
+
+ case AME_INFO_ALL: //Added for AME API 2.16
+ {
+ char *src = NULL;
+ char *dest = (char*)o_resp;
+ uint16_t l_length = strlen(l_sensorInfo.name) + 1 +\
+ strlen(l_sensorInfo.sensor.units) + 1 + \
+ sizeof(uint32_t) + sizeof(uint32_t);
+ // Check length
+ if(l_resp_length < l_length)
+ {
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ src = l_sensorInfo.name;
+ // Copy string
+ strcpy( dest, src );
+ dest += strlen(src)+1; // add string terminator
+
+ src = l_sensorInfo.sensor.units;
+ // Copy string
+ strcpy( dest, src );
+ dest += strlen(src)+1; // add string terminator
+
+ *((uint32_t *)dest) = l_sensorInfo.sensor.freq;
+ dest+= 4;
+
+ *((uint32_t *)dest) = l_sensorInfo.sensor.scalefactor;
+ dest+= 4;
+
+ *io_resp_length = (uint8_t) ((uint32_t)dest - (uint32_t)o_resp);
+ break;
+ }
+
+ default:
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ } // End of switch case
+ } while (0);
+ return l_rc;
+}
+
+// Function Specification
+//
+// Name: amester_api
+//
+// Description: amester entry point for ipmicommand 0x3C
+//
+// Task Flags:
+//
+// End Function Specification
+uint8_t amester_api( const IPMIMsg_t * i_msg,
+ uint16_t * io_resp_length,
+ uint8_t * o_resp )
+{
+ uint8_t l_rc = COMPCODE_NORMAL;
+ uint8_t l_temp_buffer[ sizeof(sensor_info_t) ];
+ sensor_t *l_sensor_ptr = NULL;
+ uint16_t l_sensor_id = 0; // sensor id
+ uint16_t l_sensor_count = 0; // sensor count
+ uint8_t l_sensor_type = 0; // sensor type
+ uint16_t l_maxlen = 0, l_retlen = 0; // for echo command and 0xff command
+ uint16_t l_resp_length = *io_resp_length;
+ sensorrec_t SensorInfo;
+
+ switch( i_msg->au8CmdData_ptr[0] )
+ {
+ // commands 0x01 ~ 0x1B are DEPRECATED except 0x07, 0x0A
+
+ case 0x07: // Get Multiple Sensor Data
+ {
+ uint16_t l_in; // input pointer
+ uint16_t l_out=0; // output pointer
+ char *t;
+ int k;
+ l_rc = COMPCODE_NORMAL;; // assume no error
+
+ // Process each sensor in turn
+ for (l_in = 1; l_in + 1 < i_msg->u8CmdDataLen; l_in=l_in+2)
+ {
+ // exit when a return message is filled. -1 is for IPMI return code
+ if (l_out + AME_SDRS > IPMI_MAX_MSG_SIZE - 1) break;
+
+ // Get the next sensor
+ l_sensor_id = CONVERT_UINT8_ARRAY_UINT16(i_msg->au8CmdData_ptr[l_in],
+ i_msg->au8CmdData_ptr[l_in+1]);
+ l_sensor_ptr = getSensorByGsid(l_sensor_id);
+ if(l_sensor_ptr == NULL)
+ {
+ // Mark which sensor number does not exist
+ o_resp[0] = (uint8_t)(l_in >> 8);
+ o_resp[1] = (uint8_t)(l_in);
+ *io_resp_length = 2;
+ l_rc = COMPCODE_DEST_UNAVAILABLE;
+ break;
+ }
+
+ /* Get a snap-shot of this sensors registers */
+ /* This copy is required so the bytes in each field are self-consistent
+ since the AME interrupt can modify them at any time. Note that it is
+ possible that the fields are not consistent with each other, but this
+ is how Amester has always been. Use traces to get a consistent view.*/
+ SensorInfo.timestamp=G_current_tick;
+ SensorInfo.updates=l_sensor_ptr->update_tag;
+ SensorInfo.accumulated_value=l_sensor_ptr->accumulator;
+ SensorInfo.value=l_sensor_ptr->sample;
+ SensorInfo.value_min=l_sensor_ptr->sample_min;
+ SensorInfo.value_max=l_sensor_ptr->sample_max;
+ memcpy(&SensorInfo.status,&l_sensor_ptr->status,sizeof(uint16_t));
+ SensorInfo.test=0; //TODO: This field is not supported for now. Maybe need to change in the future.
+
+ // Copy to output buffer.
+ t=(char *)&SensorInfo;
+ for (k=0;k<AME_SDRS;k++) o_resp[l_out++]=*t++;
+
+ *io_resp_length = l_out;
+
+ } // for each sensor
+
+ break;
+ };
+
+ case 0x0a: // Get API version
+ o_resp[0] = AME_API_MAJ;
+ o_resp[1] = AME_API_MIN;
+ *io_resp_length = 2;
+ l_rc = COMPCODE_NORMAL;
+ break;
+
+ //----------------------------------------------------------------------
+ // AME 2.16 commands
+ //----------------------------------------------------------------------
+ case 0x1c: // AME component level constants
+ // Goal is to allow 1 IPMI to get a bunch of important data at startup.
+ // Dramatically speedup Amester initialization
+
+ // Check length
+ if(l_resp_length < AME_COMPONENT_LEVEL_RSPCMD_LEN)
+ {
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+ o_resp[0] = AME_API_MAJ;
+ o_resp[1] = AME_API_MIN;
+ o_resp[2] = AME_VERSION_MAJ;
+ o_resp[3] = AME_VERSION_MIN;
+ o_resp[4] = CONVERT_UINT16_UINT8_HIGH(AME_YEAR);
+ o_resp[5] = CONVERT_UINT16_UINT8_LOW(AME_YEAR);
+ o_resp[6] = AME_MONTH;
+ o_resp[7] = AME_DAY;
+ o_resp[8] = CONVERT_UINT16_UINT8_HIGH(G_amec_sensor_count);
+ o_resp[9] = CONVERT_UINT16_UINT8_LOW(G_amec_sensor_count);
+ o_resp[10] = AMEC_TB_NUMBER_OF_TRACES;
+ *io_resp_length = AME_COMPONENT_LEVEL_RSPCMD_LEN;
+ l_rc = COMPCODE_NORMAL;
+ break;
+
+ case 0x1d:
+
+ // Check length
+ if(l_resp_length < 2)
+ {
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+ o_resp[0] = 0;
+ o_resp[1] = 0;
+ *io_resp_length = 2;
+ l_rc = COMPCODE_NORMAL;
+ break;
+
+ //Clear min/max fields in all sensors.
+ case 0x21:
+ l_sensor_ptr = NULL;
+ l_sensor_count = G_amec_sensor_count;
+
+ // clear min/max
+ uint16_t i = 0;
+ for( i = 0;i < l_sensor_count; i++)
+ {
+ l_sensor_ptr = getSensorByGsid(i);
+ sensor_clear_minmax(l_sensor_ptr);
+ }
+ *io_resp_length = 0;
+ l_rc = COMPCODE_NORMAL;
+ break;
+
+ case 0x25: // Get sensors info
+ l_rc = COMPCODE_NORMAL;
+ l_sensor_type = i_msg->au8CmdData_ptr[3];
+ l_sensor_count = G_amec_sensor_count;
+ l_sensor_id = CONVERT_UINT8_ARRAY_UINT16( i_msg->au8CmdData_ptr[1],
+ i_msg->au8CmdData_ptr[2] );
+ uint16_t j = 0;
+ uint16_t l_final_length = 0;
+
+ for( j = l_sensor_id; j < l_sensor_count; j++)
+ {
+ *io_resp_length = sizeof(sensor_info_t);
+ l_rc = amester_get_sensor_info(l_temp_buffer,io_resp_length,l_sensor_type,j);
+ if(l_rc != COMPCODE_NORMAL)
+ {
+ l_final_length = 0;
+ break;
+ }
+
+ // max response length is IPMI_MAX_MSG_SIZE
+ if( ((l_final_length+(*io_resp_length)) < IPMI_MAX_MSG_SIZE) &&
+ ((l_final_length+(*io_resp_length)) < l_resp_length ) )
+ {
+ memcpy( o_resp, l_temp_buffer, *io_resp_length); // Copy to final output buffer
+ o_resp += (*io_resp_length);
+ l_final_length = l_final_length+(*io_resp_length);
+ }
+ else
+ {
+ break;
+ }
+ }
+ *io_resp_length = l_final_length;
+ break;
+
+ // Trace buffer commands
+ // Get trace buffer configuration
+ case 0x30:
+ amec_tb_cmd_info(i_msg,o_resp,io_resp_length,&l_rc);
+ break;
+
+ // Configure TB
+ case 0x31:
+ amec_tb_cmd_set_config(i_msg,o_resp,io_resp_length,&l_rc);
+ break;
+
+ // Read TB
+ // Input is an index into the buffer.
+ // Output is a full-sized response, possibly wrapping around at end of buffer.
+ case 0x32:
+ amec_tb_cmd_read(i_msg,o_resp,io_resp_length,&l_rc);
+ break;
+
+ // Start recording TB
+ case 0x33:
+ amec_tb_cmd_start_recording(i_msg,o_resp,io_resp_length,&l_rc);
+ break;
+
+ // Stop recording TB
+ case 0x34:
+ amec_tb_cmd_stop_recording(i_msg,o_resp,io_resp_length,&l_rc);
+ break;
+
+ // Get sensor table, not support
+ case 0x35: //No support
+ *io_resp_length = 0;
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+
+ // Get SCOM table, not support
+ case 0x36: //No support
+ *io_resp_length = 0;
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+
+ // Return all configurable parameters for a trace
+ case 0x3f:
+ amec_tb_cmd_get_config(i_msg,o_resp,io_resp_length,&l_rc);
+ break;
+
+ // Get number of parameters
+ case 0x40:
+ amec_parm_get_number(i_msg,o_resp,io_resp_length,&l_rc);
+ break;
+
+ // Return configuration of parameters starting with a given guid
+ case 0x41:
+ amec_parm_get_config(i_msg,o_resp,io_resp_length,&l_rc);
+ break;
+
+ // Read parameter
+ case 0x42:
+ amec_parm_read(i_msg,o_resp,io_resp_length,&l_rc);
+ break;
+
+ // Write parameter
+ case 0x43:
+ amec_parm_write(i_msg,o_resp,io_resp_length,&l_rc);
+ break;
+
+ // Partition management
+ case 0x50: //No support
+ *io_resp_length = 0;
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+
+ // Note: Amester uses the echo command to figure out how much data it is
+ // allowed to send in 1 message to OCC.
+ case 0xfe: //echo
+ l_maxlen = IPMI_MAX_MSG_SIZE - 1; // -1 for completion code
+ l_retlen = l_maxlen;
+
+ // Pick the smaller of the input length and max output length.
+ if (i_msg->u8CmdDataLen < l_maxlen)
+ {
+ l_retlen = i_msg->u8CmdDataLen;
+ }
+
+ // Check length
+ if(l_resp_length < l_retlen)
+ {
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ l_rc = COMPCODE_NORMAL; /* assume no error */
+ // Copy back as much of the input message as possible.
+ memcpy( o_resp, i_msg->au8CmdData_ptr, l_retlen);
+ *io_resp_length = l_retlen;
+ break;
+
+ // Note: Amester uses this command to find out the maximum length output
+ // message OCC supports.
+ case 0xff:
+ l_maxlen = IPMI_MAX_MSG_SIZE - 1; // -1 for completion code
+
+ if (i_msg->u8CmdDataLen == 3)
+ {
+ l_maxlen = CONVERT_UINT8_ARRAY_UINT16( i_msg->au8CmdData_ptr[1],
+ i_msg->au8CmdData_ptr[2]);
+ }
+
+ if (l_maxlen > IPMI_MAX_MSG_SIZE -1)
+ {
+ l_maxlen = IPMI_MAX_MSG_SIZE -1;
+ }
+
+ // Check length
+ if(l_resp_length < l_maxlen)
+ {
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ l_rc = COMPCODE_NORMAL; /* assume no error */
+ for (i = 0; i<l_maxlen; i++)
+ {
+ o_resp[i] = i;
+ }
+ *io_resp_length = l_maxlen;
+ break;
+
+ default:
+ *io_resp_length = 0;
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ }
+
+ return l_rc;
+}
+
+
+// Function Specification
+//
+// Name: amester_manual_throttle
+//
+// Description: Amester interface entry point for ipmicommand 0x3B
+//
+// Task Flags:
+//
+// End Function Specification
+uint8_t amester_manual_throttle( const IPMIMsg_t * i_msg,
+ uint16_t * io_resp_length,
+ uint8_t * o_resp )
+
+{
+ /*------------------------------------------------------------------------*/
+ /* Local variables */
+ /*------------------------------------------------------------------------*/
+ uint8_t l_rc,temp1,temp2;
+ uint16_t l_resp_length = *io_resp_length;
+ uint16_t i,j,cc,idx,temp16;
+ uint16_t k;
+ uint32_t temp32a;
+ uint32_t *temp32;
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ switch (i_msg->au8CmdData_ptr[0])
+ {
+ case 0x03: // CPU(s) Present Bit Mask
+ // The CPU Present Bit Mask is now being generated by the
+ // PROC component of OCC.
+
+ // Check length
+ if(l_resp_length < 2)
+ {
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ o_resp[0] = CONVERT_UINT32_UINT8_UPPER_HIGH( G_present_hw_cores);
+ o_resp[1] = CONVERT_UINT32_UINT8_UPPER_LOW( G_present_hw_cores);
+ *io_resp_length = 2;
+ l_rc = COMPCODE_NORMAL;
+ break;
+
+ case 0x04: // Get last throttle value sent to CPU 0. DEPRECATED.
+ *io_resp_length = 0;
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+
+ case 0x05: // Get AME enable/disable flag (old style interface...do not use), no support
+ *io_resp_length = 0;
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+
+ case 0x06: // Get new PTVR (Power Threshold Vector Request), no support
+ *io_resp_length = 0;
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+
+ case 0x07: // Write individual AME parameters
+ switch (i_msg->au8CmdData_ptr[1])
+ {
+
+ case 20: // parameter 20: Set Probe Parameters
+ {
+ if (i_msg->au8CmdData_ptr[2]> (NUM_AMEC_FW_PROBES-1))
+ {
+ o_resp[0]=i_msg->au8CmdData_ptr[2];
+ *io_resp_length=1;
+ l_rc=COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+ if (i_msg->au8CmdData_ptr[3] < 1)
+ {
+ o_resp[0]=i_msg->au8CmdData_ptr[2];
+ *io_resp_length=1;
+ l_rc=COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ temp32a=((uint32_t)i_msg->au8CmdData_ptr[4]<<24)+((uint32_t)i_msg->au8CmdData_ptr[5]<<16);
+ temp32a=temp32a+((uint32_t)i_msg->au8CmdData_ptr[6]<<8)+((uint32_t)i_msg->au8CmdData_ptr[7]);
+ temp32=(uint32_t*)temp32a;
+
+ g_amec->ptr_probe250us[i_msg->au8CmdData_ptr[2]]=temp32;
+ g_amec->size_probe250us[i_msg->au8CmdData_ptr[2]]=i_msg->au8CmdData_ptr[3];
+ g_amec->index_probe250us[i_msg->au8CmdData_ptr[2]]=0; // Reset index
+
+ o_resp[0]=i_msg->au8CmdData_ptr[2]; // Return probe #
+ *io_resp_length=1;
+ l_rc = COMPCODE_NORMAL;
+ break;
+ };
+
+ case 22: // parameter 22: Analytics parameters
+ {
+ g_amec->analytics_group=i_msg->au8CmdData_ptr[2]; // Set group
+ g_amec->analytics_chip=i_msg->au8CmdData_ptr[3]; // Select which chip to analyze
+ g_amec->analytics_option=i_msg->au8CmdData_ptr[4]; // Select which option
+ g_amec->analytics_total_chips=i_msg->au8CmdData_ptr[5]; // Select total number of chips
+ g_amec->analytics_slot=i_msg->au8CmdData_ptr[6]; // Select time slot to read data
+ o_resp[0]=i_msg->au8CmdData_ptr[2];
+ o_resp[1]=i_msg->au8CmdData_ptr[3];
+ o_resp[2]=i_msg->au8CmdData_ptr[4];
+ o_resp[3]=i_msg->au8CmdData_ptr[5];
+ o_resp[4]=i_msg->au8CmdData_ptr[6];
+ *io_resp_length=5;
+ l_rc = COMPCODE_NORMAL;
+ break;
+ }
+
+ case 23: // parameter 23: CPM calibration parameters
+ {
+ // g_amec->cpms_enabled=i_msg->au8CmdData_ptr[2]; // Enable CPMs
+ o_resp[0]=i_msg->au8CmdData_ptr[2];
+ *io_resp_length=1;
+ l_rc = COMPCODE_NORMAL;
+ break;
+ }
+
+
+ case 24: // parameter 24: set ambient and fan speed sensors
+ {
+ // Set ambient temperature (8 bits)
+ temp16=(uint16_t)i_msg->au8CmdData_ptr[2];
+ sensor_update(AMECSENSOR_PTR(TEMPAMBIENT), temp16);
+ // Set average fan speed (16 bits)
+ temp16=((uint16_t)i_msg->au8CmdData_ptr[3]<<8)+(uint16_t)i_msg->au8CmdData_ptr[4];
+ sensor_update(AMECSENSOR_PTR(FANSPEEDAVG), temp16);
+ o_resp[0]=i_msg->au8CmdData_ptr[2];
+ o_resp[1]=i_msg->au8CmdData_ptr[3];
+ o_resp[2]=i_msg->au8CmdData_ptr[3];
+ *io_resp_length=3;
+ l_rc = COMPCODE_NORMAL;
+ break;
+ }
+
+
+ case 29: // parameter 29: Control vector recording modes and stream rates.
+ {
+ g_amec->stream_vector_rate=255; // First step is to set an invalid rate so no recording done at all
+ g_amec->stream_vector_mode=0; // Also is to assure NO recording during parameter changes
+ g_amec->stream_vector_group=i_msg->au8CmdData_ptr[4]; // Choose group #
+ g_amec->write_stream_index=(uint32_t)CONVERT_UINT8_ARRAY_UINT16(i_msg->au8CmdData_ptr[5],i_msg->au8CmdData_ptr[6]);
+ g_amec->stream_vector_delay=(uint32_t)CONVERT_UINT8_ARRAY_UINT16(i_msg->au8CmdData_ptr[7],i_msg->au8CmdData_ptr[8]);
+ g_amec->stream_vector_mode=i_msg->au8CmdData_ptr[2]; // Choose mode
+
+ switch (g_amec->stream_vector_group)
+ {
+ case 45: //group 45 decimal (amec_analytics support)
+ g_amec->stream_vector_map[0]=0; // Leave space for 250usec time stamp
+ k = 1;
+ for (i=0; i<=(STREAM_VECTOR_SIZE_EX-2); i++)
+ {
+ g_amec->stream_vector_map[k++] = &g_amec->analytics_array[i];
+ }
+ //gpEMP->stream_vector_map[64]=(void *) 0xffffffff; // Termination of partial vector
+ g_amec->analytics_group=45;
+ g_amec->analytics_bad_output_count=2; // drop first 2 frames of output
+ break;
+
+ default:
+ break;
+ }
+
+ // Final step is to set a valid rate to begin recording at
+ g_amec->stream_vector_rate=i_msg->au8CmdData_ptr[3]; // Choose stream rate
+ g_amec->recordflag=1; // Recording is now valid
+ *io_resp_length = 1;
+ l_rc = COMPCODE_NORMAL;
+ break;
+ }
+
+ case 64: // support for THREADMODE group 44 recording
+ g_amec->analytics_threadmode=i_msg->au8CmdData_ptr[2];
+ g_amec->analytics_threadcountmax=i_msg->au8CmdData_ptr[3];
+ o_resp[0]=i_msg->au8CmdData_ptr[2];
+ o_resp[1]=i_msg->au8CmdData_ptr[3];
+ *io_resp_length=2;
+ l_rc = COMPCODE_NORMAL;
+ break;
+
+ default:
+ *io_resp_length = 0;
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ break;
+
+ case 0x08: // Read individual AME parameters
+ switch (i_msg->au8CmdData_ptr[1])
+ {
+ case 0x08: // parameter 8: Set histogram copy interval in msec (4 bytes)
+ o_resp[0] = (uint8_t)(AME_HISTOGRAM_COPY_INTERVAL>>24);
+ o_resp[1] = (uint8_t)(AME_HISTOGRAM_COPY_INTERVAL>>16);
+ o_resp[2] = (uint8_t)(AME_HISTOGRAM_COPY_INTERVAL>>8);
+ o_resp[3] = (uint8_t)(AME_HISTOGRAM_COPY_INTERVAL);
+ *io_resp_length = 4;
+ l_rc = COMPCODE_NORMAL;
+ break;
+
+ case 20: // parameter 20: Read Probe Parameters
+ {
+ if (i_msg->au8CmdData_ptr[2]> (NUM_AMEC_FW_PROBES-1))
+ {
+ o_resp[0]=i_msg->au8CmdData_ptr[2];
+ *io_resp_length=1;
+ l_rc=COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+ o_resp[1]=g_amec->size_probe250us[i_msg->au8CmdData_ptr[2]]; // Return size of object read by probe in bytes
+ temp32=g_amec->ptr_probe250us[i_msg->au8CmdData_ptr[2]]; // Get copy of 32 bit probe ptr
+ temp32a=(uint32_t)temp32;
+ o_resp[5]=(uint8_t)temp32a;
+ o_resp[4]=(uint8_t)((uint32_t)temp32a>>8);
+ o_resp[3]=(uint8_t)((uint32_t)temp32a>>16);
+ o_resp[2]=(uint8_t)((uint32_t)temp32a>>24);
+ o_resp[0]=i_msg->au8CmdData_ptr[2]; // Return probe #
+ *io_resp_length=6;
+ l_rc=COMPCODE_NORMAL;
+ break;
+ };
+
+ case 22: // parameter 22: Analytics parameters
+ o_resp[0]=g_amec->analytics_group;
+ o_resp[1]=g_amec->analytics_chip;
+ o_resp[2]=g_amec->analytics_option;
+ o_resp[3]=g_amec->analytics_total_chips;
+ o_resp[4]=g_amec->analytics_slot;
+ *io_resp_length=5;
+ l_rc = COMPCODE_NORMAL;
+ break;
+
+ case 23: // parameter 23: CPM parameters
+ // o_resp[0]=g_amec->cpms_enabled;
+ // o_resp[1]=g_amec->cpm_active_core;
+ // o_resp[2]=g_amec->cpm_cal_state;
+ // o_resp[3]=g_amec->cpm_core_state;
+ // o_resp[4]=g_amec->cpm_measure_state;
+ // o_resp[5]=g_amec->cpm_cal_count;
+ *io_resp_length=6;
+ l_rc = COMPCODE_NORMAL;
+ break;
+
+ case 29: // parameter 29: Stream recording control parameters
+ o_resp[0]=(uint8_t)(g_amec->stream_vector_mode);
+ o_resp[1]=(uint8_t)(g_amec->stream_vector_rate);
+ o_resp[2]=(uint8_t)(g_amec->write_stream_index>>8);
+ o_resp[3]=(uint8_t)(g_amec->write_stream_index & 0xff);
+ o_resp[4]=(uint8_t)(g_amec->stream_vector_delay>>8);
+ o_resp[5]=(uint8_t)(g_amec->stream_vector_delay & 0xff);
+ *io_resp_length=6;
+ l_rc=COMPCODE_NORMAL;
+ break;
+
+ case 37: // parameter 37: Read out (IPMI_MAX_MSG_SIZE-2*STREAM_VECTOR_SIZE) byte vector from
+ // streaming buffer
+ g_amec->read_stream_index=(uint32_t)((i_msg->au8CmdData_ptr[2]<<8)+i_msg->au8CmdData_ptr[3]);
+ temp1=i_msg->au8CmdData_ptr[4];
+ temp2=i_msg->au8CmdData_ptr[5];
+ if (g_amec->read_stream_index > (STREAM_BUFFER_SIZE-1*STREAM_VECTOR_SIZE_EX))
+ {
+ o_resp[0]=i_msg->au8CmdData_ptr[2];
+ *io_resp_length=1;
+ l_rc=COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+ if (temp1 > 1) // No averaging is allowed when using large read sizes
+ {
+ o_resp[0]=i_msg->au8CmdData_ptr[4];
+ *io_resp_length=1;
+ l_rc=COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+ if (temp2 > 0)
+ {
+ o_resp[0]=i_msg->au8CmdData_ptr[5];
+ *io_resp_length=1;
+ l_rc=COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+ if (g_amec->write_stream_index >= g_amec->read_stream_index)
+ {
+ temp32a=g_amec->write_stream_index-g_amec->read_stream_index;
+ }
+ else
+ {
+ temp32a=STREAM_BUFFER_SIZE+g_amec->write_stream_index-g_amec->read_stream_index;
+ }
+ if (temp32a < 1*STREAM_VECTOR_SIZE_EX)
+ {
+ o_resp[0]=1; // Indicate insufficient data, but return a zero return code
+ *io_resp_length=STREAM_VECTOR_SIZE_EX+3; // # of bytes (STREAM_VECTOR_SIZE is in 16 bit words)
+ l_rc=COMPCODE_NORMAL;
+ break;
+ }
+ o_resp[0]=0; // Indicate sufficient data
+ i=0;
+ j=1*STREAM_VECTOR_SIZE_EX; // used to be 10*STREAM_VECTOR_SIZE_EX
+ cc=3; // Begin just past return code and time stamp
+
+ for(idx = i; idx < j; idx++) // Skip first 1 entry: either write_index and time stamp
+ {
+ temp16 = (uint16_t)g_amec->ptr_stream_buffer[g_amec->read_stream_index + idx];
+ o_resp[cc] = (temp16 >> 8);
+ o_resp[cc + 1] = (temp16 & 0xff);
+ cc = cc + 2; // output index
+ }
+ if(i_msg->au8CmdData_ptr[7] == 0)
+ {
+ temp16 = g_amec->ptr_stream_buffer[g_amec->read_stream_index]; // Send back time stamp
+ } else
+ {
+ temp16 = g_amec->write_stream_index; // Send back write stream index
+ }
+ o_resp[1] = (uint8_t)(temp16 >> 8);
+ o_resp[2] = (uint8_t)(temp16 & 0xff);
+ *io_resp_length = 3 + 2 * (1 * STREAM_VECTOR_SIZE_EX); // # of bytes (STREAM_VECTOR_SIZE_EX is in 16 bit words)
+ l_rc = COMPCODE_NORMAL;
+ break;
+
+ case 64: // support for THREADMODE group 45 recording
+ o_resp[0]=(uint8_t)(g_amec->analytics_threadmode);
+ o_resp[1]=(uint8_t)(g_amec->analytics_threadcountmax);
+ *io_resp_length=2;
+ l_rc=COMPCODE_NORMAL;
+ break;
+
+ default:
+ *io_resp_length = 0;
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ }
+ break;
+
+ default:
+ *io_resp_length = 0;
+ l_rc = COMPCODE_PARAM_OUT_OF_RANGE;
+ break;
+ } // end of switch
+
+ return l_rc;
+}
+
+// Function Specification
+//
+// Name: AMEC_entry_point
+//
+// Description: Amester interface entry point
+//
+// Task Flags:
+//
+// End Function Specification
+uint8_t amester_entry_point( const IPMIMsg_t * i_msg,
+ uint16_t * io_resp_length,
+ uint8_t * o_resp)
+
+{
+ uint8_t l_rc = COMPCODE_NORMAL;
+
+ do
+ {
+ if( (i_msg == NULL) ||
+ (io_resp_length == NULL) ||
+ (o_resp == NULL) )
+ {
+ l_rc = COMPCODE_UNSPECIFIED;
+ break;
+ }
+
+ switch (i_msg->u8Cmd)
+ {
+ case 0x3C:
+ l_rc = amester_api( i_msg, io_resp_length, o_resp);
+ break;
+
+ case 0x3B:
+ l_rc = amester_manual_throttle( i_msg, io_resp_length, o_resp);
+ break;
+
+ default:
+ l_rc = COMPCODE_CMD_UNKNOWN;
+ break;
+ }
+ } while (0);
+
+ return l_rc;
+}
+
+amec_tb_t* AMEC_tb_get_by_guid(const AMEC_TB_GUID i_guid)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ amec_tb_t* l_tb_ptr = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ if(i_guid > AMEC_TB_NUMBER_OF_TRACES)
+ {
+ //TRACE(g_trac_amec,"E>amec_tb_get_by_guid:Invalid GUID (%d) max GUID supported at the moment is (%d)",i_guid,g_amec_tb_count);
+ break;
+ }
+ //traces are arranged in an array by GUID
+ l_tb_ptr = &g_amec_tb_list[i_guid];
+
+ } while( 0 );
+
+ return l_tb_ptr;
+}
+
+//
+// Commands that run during AME interrupt time
+//
+void amec_tb_record(const AMEC_TB_GUID i_guid)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ UINT8 *l_w; // pointer for tracebuffer writing
+ UINT16 l_i;
+ sensor_t *l_s;
+ UINT32 l_totalbytes;
+ amec_parm_t *l_parm;
+ UINT8 *l_src_ptr;
+ AMEC_PARM_GUID l_parm_guid;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Record OCA from last 32 ms
+ if(G_dcom_slv_inbox_rx.tb_record)
+ {
+ // Check for valid tb write entry index
+ if(g_amec_tb_list[i_guid].write < g_amec_tb_list[i_guid].entry_n)
+ {
+ l_w = g_amec_tb_list[i_guid].bytes + g_amec_tb_list[i_guid].write * g_amec_tb_list[i_guid].entry_size;
+ // Write the tracked sensors
+ for(l_i = 0; l_i < g_amec_tb_list[i_guid].sensors_n; l_i++)
+ {
+ l_s = getSensorByGsid(g_amec_tb_list[i_guid].sensors_num[l_i]);
+ switch(g_amec_tb_list[i_guid].sensors_field[l_i])
+ {
+ case 0:
+ { //value
+ *l_w++ = (UINT8)(l_s->sample >> 8);
+ *l_w++ = (UINT8)(l_s->sample);
+ break;
+ }
+ case 1:
+ { //min
+ *l_w++ = (UINT8)(l_s->sample_min >> 8);
+ *l_w++ = (UINT8)(l_s->sample_min);
+ break;
+ }
+ case 2:
+ { //max
+ *l_w++ = (UINT8)(l_s->sample_max >> 8);
+ *l_w++ = (UINT8)(l_s->sample_max);
+ break;
+ }
+ case 3:
+ { //accumulator
+ *l_w++ = (UINT8)(l_s->accumulator >> 24);
+ *l_w++ = (UINT8)(l_s->accumulator >> 16);
+ *l_w++ = (UINT8)(l_s->accumulator >> 8);
+ *l_w++ = (UINT8)(l_s->accumulator);
+ break;
+ }
+ case 4:
+ { //update tag
+ *l_w++ = (UINT8)(l_s->update_tag >> 24);
+ *l_w++ = (UINT8)(l_s->update_tag >> 16);
+ *l_w++ = (UINT8)(l_s->update_tag >> 8);
+ *l_w++ = (UINT8)(l_s->update_tag);
+ break;
+ }
+ case 5:
+ { //test (not available in POWER8)
+ *l_w++ = (UINT8)0;
+ *l_w++ = (UINT8)0;
+ break;
+ }
+ case 6:
+ { //rcnt
+ *l_w++ = (UINT8)(g_amec->r_cnt >> 24);
+ *l_w++ = (UINT8)(g_amec->r_cnt >> 16);
+ *l_w++ = (UINT8)(g_amec->r_cnt >> 8);
+ *l_w++ = (UINT8)(g_amec->r_cnt);
+ break;
+ }
+ default:
+ break;
+ }
+ } // write sensors
+
+ // Write the tracked parameters
+ for(l_i = 0; l_i < g_amec_tb_list[i_guid].parm_n; l_i++)
+ {
+ l_parm_guid = g_amec_tb_list[i_guid].parm_num[l_i];
+ if(g_amec_parm_list[l_parm_guid].preread) amec_parm_preread(l_parm_guid); // get latest version
+ l_parm = &g_amec_parm_list[l_parm_guid];
+ l_totalbytes = l_parm->length * l_parm->vector_length;
+ l_src_ptr = l_parm->value_ptr;
+ while(l_totalbytes--)
+ {
+ *l_w++ = *l_src_ptr++;
+ }
+ }
+
+ // Advance the write pointer and decide if recording should stop
+ g_amec_tb_list[i_guid].write++; // Signal this entry is ready for reading
+ if(g_amec_tb_list[i_guid].write >= g_amec_tb_list[i_guid].entry_n)
+ {
+ if(g_amec_tb_continuous)
+ {
+ // Start at beginning of trace
+ g_amec_tb_list[i_guid].write = 0;
+ } else
+ {
+ // Stop recording if this trace is configured
+ if(g_amec_tb_list[i_guid].entry_n) g_amec_tb_record = 0;
+ }
+ }
+ } // valid write index
+ } // end if(record)}
+}
+
+
+// Get tb config. Pack as many traces as possible
+void amec_tb_cmd_info(const IPMIMsg_t *i_psMsg,
+ UINT8 *o_pu8Resp,
+ UINT16 *o_pu16RespLength,
+ UINT8 *o_retval)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ AMEC_TB_GUID l_id; // trace id
+ UINT16 l_j; // size of return message
+ CHAR *l_src; //pointer for copying name
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ l_id = (AMEC_TB_GUID) i_psMsg->au8CmdData_ptr[1];
+ l_j = 0; // write index byte for response
+
+ for(; l_id < AMEC_TB_NUMBER_OF_TRACES; l_id++)
+ {
+ if(l_j + AMEC_TB_CONFIG_SIZE >= IPMI_MAX_MSG_SIZE) break; // end of response buffer
+
+ l_src = g_amec_tb_list[l_id].name;
+ while(*l_src != 0)
+ {
+ o_pu8Resp[l_j++] = *l_src++;
+ } /* copy string up until \0 */
+ o_pu8Resp[l_j++] = '\0'; /* add string terminator */
+
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_tb_list[l_id].freq >> 24);
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_tb_list[l_id].freq >> 16);
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_tb_list[l_id].freq >> 8);
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_tb_list[l_id].freq);
+ // has_scoms field from POWER7 is always 0 on POWER8
+ o_pu8Resp[l_j++] = 0;
+ }
+ *o_pu16RespLength=l_j;
+ *o_retval=COMPCODE_NORMAL;
+ return;
+}
+
+
+void amec_tb_cmd_set_config(const IPMIMsg_t *i_psMsg,
+ UINT8 *o_pu8Resp,
+ UINT16 *o_pu16RespLength,
+ UINT8 *o_retval)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ UINT8 l_i;
+ UINT16 l_sensors_n;
+ UINT16 l_oca_n;
+ UINT16 l_num_index;
+ UINT16 l_field_index;
+ UINT8 l_valid_sockets = 0;
+ UINT32 l_socket_bitmap = 0;
+ UINT16 l_parm_n;
+ UINT16 l_parm_index;
+ amec_parm_t *l_parm;
+ UINT8 l_count;
+ amec_tb_t *l_trace;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ *o_retval = COMPCODE_NORMAL;
+
+ //Stop recording while setting up a trace.
+ g_amec_tb_record = 0;
+
+ // 0. Parse input
+ l_trace = AMEC_tb_get_by_guid(i_psMsg->au8CmdData_ptr[1]);
+ l_sensors_n = CONVERT_UINT8_ARRAY_UINT16(
+ i_psMsg->au8CmdData_ptr[2],
+ i_psMsg->au8CmdData_ptr[3]
+ );
+ l_parm_n = CONVERT_UINT8_ARRAY_UINT16(
+ i_psMsg->au8CmdData_ptr[4],
+ i_psMsg->au8CmdData_ptr[5]
+ );
+ l_oca_n = CONVERT_UINT8_ARRAY_UINT16(
+ i_psMsg->au8CmdData_ptr[6],
+ i_psMsg->au8CmdData_ptr[7]
+ );
+ l_socket_bitmap = CONVERT_UINT8_ARRAY_UINT32(
+ i_psMsg->au8CmdData_ptr[8],
+ i_psMsg->au8CmdData_ptr[9],
+ i_psMsg->au8CmdData_ptr[10],
+ i_psMsg->au8CmdData_ptr[11]
+ );
+
+ if(l_sensors_n > AMEC_TB_SENSORS_MAX)
+ {
+ *o_retval = COMPCODE_PARAM_OUT_OF_RANGE;
+ o_pu8Resp[0] = 0; // mark second byte is bad.
+ o_pu8Resp[1] = 2; // mark second byte is bad.
+ *o_pu16RespLength = 2;
+ break;
+ }
+
+ if(l_parm_n > AMEC_TB_PARM_MAX)
+ {
+ *o_retval = COMPCODE_PARAM_OUT_OF_RANGE;
+ o_pu8Resp[0] = 0; // mark fourth byte is bad.
+ o_pu8Resp[1] = 4; //
+ *o_pu16RespLength = 2;
+ }
+
+ if(l_oca_n > OCA_MAX_ENTRIES)
+ {
+ *o_retval = COMPCODE_PARAM_OUT_OF_RANGE;
+ o_pu8Resp[0] = 0; // mark sixth byte is bad
+ o_pu8Resp[1] = 6;
+ *o_pu16RespLength = 2;
+ break;
+ }
+
+ // Count valid sockets
+ l_count = l_socket_bitmap;
+ while(l_count)
+ {
+ if(l_count & 0x01)
+ {l_valid_sockets++;}
+ l_count >>= 1;
+ }
+ if(l_valid_sockets > MAX_NUM_CHIPS)
+ {
+ l_valid_sockets = MAX_NUM_CHIPS;
+ }
+
+ l_trace->entry_size = 0;
+
+ // Set pointers to input
+ l_num_index = 12; // start of sensor numbers
+ l_field_index = 12 + 2 * l_sensors_n; // start of sensor fields
+ l_parm_index = l_field_index + l_sensors_n; // start of parameters
+
+ // Read sensor configuration
+ for(l_i = 0; l_i < l_sensors_n; l_i++)
+ {
+ l_trace->sensors_num[l_i] = CONVERT_UINT8_ARRAY_UINT16(
+ i_psMsg->au8CmdData_ptr[l_num_index],
+ i_psMsg->au8CmdData_ptr[l_num_index + 1]
+ );
+ l_trace->sensors_field[l_i] = i_psMsg->au8CmdData_ptr[l_field_index];
+
+ if(l_trace->sensors_num[l_i] >= G_amec_sensor_count)
+ {
+ *o_retval = COMPCODE_PARAM_OUT_OF_RANGE;
+ o_pu8Resp[0] = (UINT8)(l_num_index >> 8); // mark which byte input is bad
+ o_pu8Resp[1] = (UINT8)(l_num_index); // mark which byte input is bad
+ *o_pu16RespLength = 2;
+ break;
+ }
+
+ if(l_trace->sensors_field[l_i] > 6)
+ {
+ *o_retval = COMPCODE_PARAM_OUT_OF_RANGE;
+ o_pu8Resp[0] = (UINT8)(l_field_index >> 8); // mark which byte input is bad
+ o_pu8Resp[1] = (UINT8)(l_field_index); // mark which byte input is bad
+ *o_pu16RespLength = 2;
+ return;
+ }
+
+ switch(l_trace->sensors_field[l_i])
+ {
+ case 0: // value
+ case 1: // min
+ case 2: // max
+ l_trace->entry_size += 2;
+ break;
+ case 3: //acc
+ l_trace->entry_size += 4;
+ break;
+ case 4: //updates
+ l_trace->entry_size += 4;
+ break;
+ case 5: //test
+ l_trace->entry_size += 2;
+ break;
+ case 6: //rcnt
+ l_trace->entry_size += 4;
+ break;
+ default:
+ break;
+ }
+
+ l_num_index += 2;
+ l_field_index++;
+ }
+
+ if(*o_retval) break;
+
+ // Record number of sensors in this trace
+ l_trace->sensors_n = l_sensors_n;
+
+ // Read Parameter configuration
+ for(l_i = 0; l_i < l_parm_n; l_i++)
+ {
+ l_trace->parm_num[l_i] = CONVERT_UINT8_ARRAY_UINT16(
+ i_psMsg->au8CmdData_ptr[l_parm_index],
+ i_psMsg->au8CmdData_ptr[l_parm_index + 1]
+ );
+
+ if(l_trace->parm_num[l_i] >= AMEC_PARM_NUMBER_OF_PARAMETERS)
+ {
+ *o_retval = COMPCODE_PARAM_OUT_OF_RANGE;
+ o_pu8Resp[0] = (UINT8)(l_parm_index >> 8); // mark which byte input is bad
+ o_pu8Resp[1] = (UINT8)(l_parm_index); // mark which byte input is bad
+ *o_pu16RespLength = 2;
+ break;
+ }
+ l_parm = &g_amec_parm_list[l_trace->parm_num[l_i]];
+ l_trace->entry_size += l_parm->length * l_parm->vector_length;
+ l_parm_index += 2;
+ }
+
+ if(*o_retval) break;
+
+ // Record this number of parameters in the trace
+ l_trace->parm_n = l_parm_n;
+
+ l_trace->entry_n = l_trace->size / l_trace->entry_size;
+ l_trace->read = 0;
+ l_trace->write = 0;
+
+ *o_pu16RespLength = 0;
+ } while(0);
+
+ return;
+}
+
+void amec_tb_cmd_start_recording(const IPMIMsg_t *i_psMsg,
+ UINT8 *o_pu8Resp,
+ UINT16 *o_pu16RespLength,
+ UINT8 *o_retval)
+{
+ g_amec_tb_record = 1;
+ *o_pu16RespLength = 0;
+ *o_retval=COMPCODE_NORMAL;
+}
+
+void amec_tb_cmd_stop_recording(const IPMIMsg_t *i_psMsg,
+ UINT8 *o_pu8Resp,
+ UINT16 *o_pu16RespLength,
+ UINT8 *o_retval)
+{
+ g_amec_tb_record = 0;
+ *o_pu16RespLength = 0;
+ *o_retval=COMPCODE_NORMAL;
+}
+
+void amec_tb_cmd_read(const IPMIMsg_t *i_psMsg,
+ UINT8 *o_pu8Resp,
+ UINT16 *o_pu16RespLength,
+ UINT8 *o_retval)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ amec_tb_t *l_trace;
+ UINT16 l_i=0; // output index
+ UINT16 l_maxresponse = IPMI_MAX_MSG_SIZE - 1; // -1 since return code is 1B
+ UINT32 l_j; // index to copy from
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ *o_retval = COMPCODE_NORMAL; /* assume no error */
+
+ // Parse input command
+ l_trace = AMEC_tb_get_by_guid(i_psMsg->au8CmdData_ptr[1]);
+ if(l_trace == NULL)
+ {
+ *o_retval = COMPCODE_PARAM_OUT_OF_RANGE;
+ *o_pu16RespLength = 0;
+ break;
+ }
+ l_j = CONVERT_UINT8_ARRAY_UINT32(
+ i_psMsg->au8CmdData_ptr[2],
+ i_psMsg->au8CmdData_ptr[3],
+ i_psMsg->au8CmdData_ptr[4],
+ i_psMsg->au8CmdData_ptr[5]
+ );
+
+ // Copy bytes to be read into response buffer
+ for(l_i = 0; l_i < l_maxresponse; l_i++, l_j++)
+ {
+ if(l_j >= l_trace->size) // wrap around to beginning of buffer.
+ {
+ l_j = 0;
+ }
+ o_pu8Resp[l_i] = l_trace->bytes[l_j];
+ }
+ *o_pu16RespLength = l_i;
+ } while(0);
+}
+
+
+void amec_tb_cmd_get_config(const IPMIMsg_t *i_psMsg,
+ UINT8 *o_pu8Resp,
+ UINT16 *o_pu16RespLength,
+ UINT8 *o_retval)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ amec_tb_t *l_trace;
+ UINT8 l_i = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ do
+ {
+ *o_retval = COMPCODE_NORMAL;
+
+ l_trace = AMEC_tb_get_by_guid(i_psMsg->au8CmdData_ptr[1]);
+ if(l_trace == NULL)
+ {
+ *o_retval = COMPCODE_PARAM_OUT_OF_RANGE;
+ *o_pu16RespLength = 0;
+ break;
+ }
+
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->bytes >> 24);
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->bytes >> 16);
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->bytes >> 8);
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->bytes);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->size >> 24);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->size >> 16);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->size >> 8);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->size);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->entry_size >> 24);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->entry_size >> 16);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->entry_size >> 8);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->entry_size);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->entry_n >> 24);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->entry_n >> 16);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->entry_n >> 8);
+ o_pu8Resp[l_i++] = (UINT8)(l_trace->entry_n);
+ // 32-bit oca_offset field is always 0 on POWER8
+ o_pu8Resp[l_i++] = 0;
+ o_pu8Resp[l_i++] = 0;
+ o_pu8Resp[l_i++] = 0;
+ o_pu8Resp[l_i++] = 0;
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->write >> 24);
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->write >> 16);
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->write >> 8);
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->write);
+ // 32-bit write_oca field is always 0 on POWER8
+ o_pu8Resp[l_i++] = 0;
+ o_pu8Resp[l_i++] = 0;
+ o_pu8Resp[l_i++] = 0;
+ o_pu8Resp[l_i++] = 0;
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->read >> 24);
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->read >> 16);
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->read >> 8);
+ o_pu8Resp[l_i++] = (UINT8)((UINT32)l_trace->read);
+ o_pu8Resp[l_i++] = l_trace->sensors_n;
+ o_pu8Resp[l_i++] = l_trace->parm_n;
+ // oca_n field from POWER7 is always 0 on POWER8
+ o_pu8Resp[l_i++] = 0;
+
+ // TODO: this should move to another command
+ o_pu8Resp[l_i++] = g_amec_tb_record;
+ o_pu8Resp[l_i++] = g_amec_tb_continuous;
+ o_pu8Resp[l_i++] = (UINT8)((UINT16)AMEC_TB_SENSORS_MAX);
+ o_pu8Resp[l_i++] = (UINT8)((UINT16)OCA_MAX_ENTRIES);
+ o_pu8Resp[l_i++] = (UINT8)(MAX_NUM_CHIPS);
+ o_pu8Resp[l_i++] = (UINT8)(AMEC_TB_PARM_MAX);
+ *o_pu16RespLength = l_i;
+
+ } while(0);
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_amester.h b/src/occ_405/amec/amec_amester.h
new file mode 100644
index 0000000..8a3510f
--- /dev/null
+++ b/src/occ_405/amec/amec_amester.h
@@ -0,0 +1,327 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_amester.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 _AMEC_AMESTER_H
+#define _AMEC_AMESTER_H
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+/* Define Completion Codes (IPMI 1.5 Table 5-2) */
+#define COMPCODE_NORMAL 0x00
+#define COMPCODE_NODE_BUSY 0xC0
+#define COMPCODE_CMD_UNKNOWN 0xC1
+#define COMPCODE_CMD_INVALID_FOR_LUN 0xC2
+#define COMPCODE_TIMEOUT 0xC3
+#define COMPCODE_OUT_OF_SPACE 0xC4
+#define COMPCODE_RESERVATION_CANCELLED 0xC5
+#define COMPCODE_REQ_DATA_TRUNCATED 0xC6
+#define COMPCODE_REQ_DATA_LEN_INVALID 0xC7
+#define COMPCODE_REQ_LEN_LIMIT_EXCEEDED 0xC8
+#define COMPCODE_PARAM_OUT_OF_RANGE 0xC9
+#define COMPCODE_REQ_BYTE_CNT_ERR 0xCA
+#define COMPCODE_OBJ_ABSENT 0xCB
+#define COMPCODE_REQ_FIELD_INVALID 0xCC
+#define COMPCODE_CMD_ILL_FOR_SEN 0xCD
+#define COMPCODE_RESP_UNAVAILABLE 0xCE
+#define COMPCODE_REQ_DUPLICATE 0xCF
+#define COMPCODE_SDR_REPO_IN_UPD 0xD0
+#define COMPCODE_FW_IN_UPD 0xD1
+#define COMPCODE_INIT_IN_PROGRESS 0xD2
+#define COMPCODE_DEST_UNAVAILABLE 0xD3
+#define COMPCODE_WRONG_PRIV 0xD4
+#define COMPCODE_CUR_NOT_SUPPORT 0xD5
+#define COMPCODE_UNSPECIFIED 0xFF
+
+//Habanero uses IPMI, which is constrained to 256 Byte IPMI response.
+//This will slow down the Amester connection on FSP-based systems
+#define IPMI_MAX_MSG_SIZE 246 // BMC size
+#define AMEC_AME_CMD_HEADER_SZ 2
+
+// Autonomic Management of Energy (AME) Parameters
+#define AME_API_MAJ 2 // API version major
+#define AME_API_MIN 26 // API version minor
+
+#define AME_VERSION_MAJ 7 // Major Version (e.g. Ver. 1.4 has MAJ=1)
+#define AME_VERSION_MIN 27 // Minor Version (e.g. Ver. 1.4 has MIN=4)
+
+#define AME_YEAR 2015 // Year of Release (e.g. 2006)
+#define AME_MONTH 4 // Month of Release (e.g. September=9)
+#define AME_DAY 2 // Day of Release
+
+#define AME_SDRS 22 // AME Sensor Data Record Size: 18 bytes
+
+// AME data types for AME_GetInfo_*() functions
+#define AME_INFO_NAME 0
+#define AME_INFO_FREQ 1
+#define AME_INFO_UNITS 2
+#define AME_INFO_SCALE 3
+#define AME_INFO_KIND 4
+#define AME_INFO_ALL 5
+
+#define COMMON_MAX_MTU_SIZE 2056
+
+// The command response length
+#define AME_COMPONENT_LEVEL_RSPCMD_LEN 11
+
+// Histogram copy interval in milliseconds (default to 8 seconds)
+#define AME_HISTOGRAM_COPY_INTERVAL 8000
+
+// WARNING -> STREAM_BUFFER_SIZE must be a perfect multiple of the vector size.
+#define STREAM_VECTOR_SIZE 32 // # of 16 bit elements in a stream vector-> must be a power of 2
+#define SHIFT_VECTOR_SIZE 5 // Log base 2 of STREAM_VECTOR_SIZE for shifting
+#define INJECTION_BUFFER_SIZE 32 // Size of injection buffer (must be a power of 2)
+#define STREAM_VECTOR_SIZE_EX 74 // # of 16 bit elements in a stream vector
+#define STREAM_BUFFER_SIZE (40*1*STREAM_VECTOR_SIZE_EX) // Stream buffer size in 16 bit samples for recording real time data to stream to Amester
+#define MAX_SENSORS_ANALYTICS 134 // Maximum sensors making up the analytics group 45 (includes all Centaur data & L4 data & supports 12 cores)
+#define MSA MAX_SENSORS_ANALYTICS
+
+#define OCA_MAX_ENTRIES 0 // no POWER7 OCA on POWER8
+#define AMEC_TB_SENSORS_MAX 40
+#define AMEC_TB_PARM_MAX 40
+
+// Macro for dividing two UINT32
+// Returns a 32-bit value with the quotient of the division.
+#define UTIL_DIV32(I_NUM, I_DEN) (((UINT32)(I_NUM)) / ((UINT32)(I_DEN)))
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+typedef struct
+{
+ /** The IPMI command ID */
+ uint8_t u8Cmd;
+ /** The IPMI command data length */
+ uint16_t u8CmdDataLen;
+ /** the IPMI command data (including completion code) */
+ uint8_t *au8CmdData_ptr;
+} IPMIMsg_t;
+
+typedef struct sensorrec
+{
+ uint32_t timestamp;
+ uint32_t updates;
+ uint32_t accumulated_value;
+ uint16_t value;
+ uint16_t value_min;
+ uint16_t value_max;
+ uint16_t status; // bit 0, LSB: calibration complete on this sensor (=1);
+ // no calibration complete (=0)
+ // bit 1: histogram gets updated (=1);
+ // histogram is frozen (=0)
+ // bit 2: histogram gets reset (=1);
+ // histogram not being reset (=0)
+ // WARNING -> bit 2 only takes effect when bit 1
+ // is toggled high. As soon as the histogram of
+ // interest is reset, bit 2 is cleared to a 0
+ // automatically. It is expected that the
+ // external entity will carry out a reset, first
+ // by setting bit 1 to a 0 to freeze updating,
+ // then set bit 2 to a 1 to enable a reset, and
+ // then set bit 1 to a 1 to enable a reset and
+ // immediate updating again from a known state
+ // of 0 in all counters.
+ // bit 3: select buffering area to be a time series
+ // trace (=1) or a histogram (=0) (msw324)
+ // bit 4: if set to 1, time series trigger is armed;
+ // if =0, trigger happened (msw354)
+ // bit 5: if set to 1, then time series buffer trace
+ // ptr was reset to 0; this bit is set to 0
+ // whenever the next histogram snapshot interval
+ // arrives. If the bit stays at 0, and the
+ // next histogram snapshot interval arrives,
+ // then the update tag is not incremented. This
+ // allows for much shorter intervals when using
+ // exclusively time series modes for all the
+ // sensors with a buffer because the Amester
+ // never sees the update tag keep getting
+ // incremented once the recording of each time
+ // trace is completed. msw357
+ // bit 6: if set to 1, this forces all sensor snapshots
+ // to occur simultaneously in time msw366
+ // This is important for histograms to be
+ // compared. if set to 0, snapshots will be
+ // spreadout with one done every 64msec once
+ // the snap-shot interval is finished. This
+ // flattens out the cycles for a large number
+ // of sensors being monitored for time-tracing
+ // where the contents of the histogram/time
+ // trace buffer aren't changing once the trace
+ // has finished recording, so snapshotting all
+ // these sensors at the same time instant
+ // is not essential. Normally, if all histograms
+ // are in use, set this bit to 1. If all
+ // time-series are in used, set this to 0. If
+ // mixed, be very careful about the choice!
+ // bits 11 to 13:
+ // encodes function to be performed in creating a vector
+ // sensor's sample_reg output.
+ // 000 -> find max of vector elements
+ // 001 -> find min of vector elements
+ // 010 -> find average of vector elements
+ // 011 to 111 are available for new functions.
+ // bit 14:if set to 1, high resolution mode is used for
+ // histograms and tracing on all vector
+ // sensors. All samples of the vector pass
+ // through add_histogram routine every time
+ // the vector is updated. if set to 0, low
+ // resolution mode is used, and only sample_reg
+ // (latest max or min of the vector) is passed
+ // through add_histogram every time.
+ // bit 15:if set to 1, this is an AME vector sensor.
+ // if set to 0, this is a normal AME scalar
+ // sensor.
+
+ uint16_t test;
+ // if bit 15 is set to 1 in the status register, the
+ // test register can only be used to support
+ // the vector sensor. In this mode, the high 8
+ // bits are used to hold two 4 bit
+ // indices of minimum values. The low 8 bits are
+ // used to hold two 4 bit indices of
+ // maximum values. Vector sensors can only hold
+ // up to 12 elements, so each 4 bit index
+ // can point to the vector index of interest.
+ // Here is a summary of what each 4 bit field
+ // shows:
+ // bits 15-12: index of minimum vector sensor
+ // value seen for all time (since
+ // last reset)
+ // bits 11-8: index of minimum vector sensor
+ // value seen for the latest time
+ // instant
+ // bits 7-4: index of maximum vector sensor
+ // value seen for all time (since
+ // last reset)
+ // bits 3-0: index of maximum vector sensor
+ // value seen for the latest time
+ // instant
+ // Vector sensors should not be longer than 12
+ // elements because one can only guard out
+ // up to 12 elements with the vector sensor
+ // enable mask and to avoid extreme cycle spikes.
+ // A RESET of this sensor will cause the test
+ // register (high and low bytes) to be set to
+ // 0xFF.
+ // if bit 15 is set to 0 in the status register, this
+ // register can be used to store anything.
+} sensorrec_t;
+
+typedef UINT8 AMEC_TB_GUID;
+typedef UINT16 AMEC_SENSOR_GUID;
+
+typedef enum
+{
+ AMEC_TB_2MS, // GUID for 2ms trace
+ AMEC_TB_250US, // GUID for 250us trace
+ AMEC_TB_NUMBER_OF_TRACES // Number of trace buffers supported
+} AMEC_TB_ENUM;
+
+typedef struct amec_tb
+{
+ // Constant properties
+
+ ///Trace name
+ CHAR* name;
+ ///Update Frequency
+ UINT32 freq;
+
+ /* Configurable properties */
+ ///Pointer to raw bytes for trace buffer
+ UINT8* bytes;
+ ///Number of raw bytes
+ UINT32 size;
+ ///Number of bytes in 1 trace record. Used to increment write pointer.
+ UINT32 entry_size;
+ ///Number of records that fit in the trace buffer. (0 to n-1 can be used)
+ UINT32 entry_n;
+ ///Record number to write next for sensor data
+ UINT32 write;
+ ///Record number for next read (not used yet)
+ UINT32 read;
+ ///Number of sensors tracked in tb
+ UINT8 sensors_n;
+ ///Number of paramters tracked in tb
+ UINT8 parm_n;
+ ///List of corresponding sensor fields tracked in this trace buffer
+ UINT8 sensors_field[AMEC_TB_SENSORS_MAX];
+ ///List of sensors tracked in this trace buffer
+ AMEC_SENSOR_GUID sensors_num[AMEC_TB_SENSORS_MAX];
+ ///List of parameters tracked
+ uint16_t parm_num[AMEC_TB_PARM_MAX];
+
+} amec_tb_t;
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+//Amester interface entry point
+uint8_t amester_entry_point( const IPMIMsg_t * i_msg,
+ uint16_t * o_resp_length,
+ uint8_t * o_resp);
+
+// Write sensor data to trace record
+// Called periodically to write next trace record with sensor data.
+void amec_tb_record(const AMEC_TB_GUID i_guid);
+
+// Get global information on traces (names, frequencies)
+// Get a list of all available trace buffers in OCC and their frequencies.
+void amec_tb_cmd_info(const IPMIMsg_t * i_psMsg, UINT8 *o_pu8Resp,UINT16 *o_pu16RespLength,UINT8 *o_retval);
+
+// Set the configuration of a trace (which sensors to trace)
+// Choose which sensors and SCOMs to trace. Choose size of trace buffer memory.
+void amec_tb_cmd_set_config(const IPMIMsg_t *i_psMsg, UINT8 *o_pu8Resp,UINT16 *o_pu16RespLength,UINT8 *o_retval);
+
+// Begin recording all configured traces
+void amec_tb_cmd_start_recording(const IPMIMsg_t *i_psMsg,UINT8 *o_pu8Resp,UINT16 *o_pu16RespLength,UINT8 *o_retval);
+
+// Stop recording all traces
+void amec_tb_cmd_stop_recording(const IPMIMsg_t *i_psMsg,UINT8 *o_pu8Resp,UINT16 *o_pu16RespLength,UINT8 *o_retval);
+
+// Get bytes from trace buffer memory
+// Returns a maximum size packet starting at a given index
+void amec_tb_cmd_read(const IPMIMsg_t *i_psMsg,UINT8 *o_pu8Resp,UINT16 *o_pu16RespLength,UINT8 *o_retval);
+
+// Returns configuration of a trace
+void amec_tb_cmd_get_config(const IPMIMsg_t *i_psMsg,UINT8 *o_pu8Resp,UINT16 *o_pu16RespLength,UINT8 *o_retval);
+
+#endif
diff --git a/src/occ_405/amec/amec_analytics.c b/src/occ_405/amec/amec_analytics.c
new file mode 100755
index 0000000..8b65f6d
--- /dev/null
+++ b/src/occ_405/amec/amec_analytics.c
@@ -0,0 +1,536 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_analytics.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 */
+
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <amec_amester.h>
+#include <amec_sys.h>
+#include <proc_data.h>
+#include <ssx.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+extern uint8_t G_occ_interrupt_type;
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+void amec_analytics_sb_recording(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t temp16 = 0;
+ uint8_t k = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Increment the internal counter here per 250us tick
+ g_amec->r_cnt++;
+
+ // Need to have reached modulo time interval to record output and also just
+ // after the analytics_slot was reached.
+ temp16 = g_amec->r_cnt - g_amec->analytics_slot;
+ temp16 = ((1<<g_amec->stream_vector_rate)-1) & temp16;
+
+ if ((temp16 == 0) && (g_amec->recordflag == 1))
+ {
+ if (g_amec->stream_vector_mode == 0) // If zero, see if timer running prior to beginning a capture
+ {
+ if (g_amec->stream_vector_delay > 1)
+ {
+ g_amec->stream_vector_delay = g_amec->stream_vector_delay - 1;
+ } else
+ {
+ if (g_amec->stream_vector_delay == 1)
+ {
+ g_amec->stream_vector_mode = 1; // Turn on 1 shot recording
+ g_amec->write_stream_index = 0; // Reset to start of buffer
+ g_amec->stream_vector_delay = 0; // Disable any further delays
+
+ // support L4 state machine and tracing being synchronized
+ if (g_amec->reset_prep != 0)
+ {
+ g_amec->cent_l4_state[g_amec->probe_l4_centaur] = 0; // Start with L4 state machine set to first state (L4_S0)
+ g_amec->cent_l4_ipl_state[g_amec->probe_l4_centaur] = 0; // Start with L4 IPL state machine set to first state (IPL_L4_S0)
+ g_amec->reset_prep = 0; // Turn off indicator of TMGT wanting to reset the OCC, which will start L4 state machine
+ g_amec->l4_powerdown_requestm = 1; // Raise indicator that the master OCC wants to carry out an L4 power down
+ }
+ }
+ }
+ } else
+ {
+ // Check is discarding initial frames due to analytics data getting averaged
+ if (g_amec->analytics_bad_output_count == 0)
+ {
+ // Stream buffer recording function done every 250usec * 2^(stream_vector_rate)
+ g_amec->ptr_stream_buffer[g_amec->write_stream_index] = (uint16_t)g_amec->r_cnt;
+ g_amec->write_stream_index++;
+ // WARNING -> The size of the vector recorded must be a precise multiple
+ // of the size of the entire stream buffer.
+ for (k = 1; k < STREAM_VECTOR_SIZE_EX; k++)
+ {
+ if (g_amec->stream_vector_map[k] == (void *)0xffffffff)
+ {
+ k = STREAM_VECTOR_SIZE_EX; // Terminate as partial vector complete
+ } else
+ {
+ temp16 = *((uint16_t * )(g_amec->stream_vector_map[k]));
+ g_amec->ptr_stream_buffer[g_amec->write_stream_index] = (uint16_t)temp16;
+ g_amec->write_stream_index++;
+ }
+ }
+ if (g_amec->write_stream_index >= STREAM_BUFFER_SIZE)
+ {
+ g_amec->write_stream_index = 0; // Reset to start of buffer
+ if (g_amec->stream_vector_mode == 1)
+ {
+ // If single shot, just rotate write ptr in last record
+ g_amec->write_stream_index = STREAM_BUFFER_SIZE - STREAM_VECTOR_SIZE_EX;
+ }
+ }
+ } else
+ {
+ g_amec->analytics_bad_output_count--; // decrement bad output counter
+ }
+ }
+ }
+}
+
+void amec_analytics_main(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint8_t i = 0;
+ uint8_t j = 0;
+ uint8_t k = 0;
+ uint8_t l = 0;
+ uint8_t m = 0;
+ uint16_t temp16 = 0;
+ uint16_t tempreg = 0;
+ uint32_t temp32 = 0;
+ uint32_t tempaccum = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // This functions is disabled by default. Need to enable analytics via
+ // Amester.
+ if (g_amec->stream_vector_rate == 0xFF)
+ {
+ return;
+ }
+
+ g_amec->packednapsleep[0] = (g_amec->proc[0].winkcnt2ms.sample<<8) +
+ g_amec->proc[0].sleepcnt2ms.sample;
+ // There are no other elements in proc[] array other than element 0
+ g_amec->packednapsleep[1] = 0;
+ g_amec->packednapsleep[2] = 0;
+ g_amec->packednapsleep[3] = 0;
+
+ switch (g_amec->analytics_group)
+ {
+ case 45: // Group 45
+
+ // Every 2msec (250usec * 2^stream_rate, default stream_rate=3), perform averaging of sensors.
+ // Averaging is required because many sensors are updated every
+ // 2msec and if they aren't properly averaged, those updates
+ // are lost in the final analytics output.
+ // The analytics group should be a correct average of the higher
+ // frequency sensor updates.
+ // (wait until OCC master collects all chips data)
+ for (i=0; i<1; i++)
+ {
+ g_amec->g44_avg[(i*MSA)+0] = (UINT32)g_amec->sys.todclock0.sample; // ptr to high 16 bits of 48bit TOD clock
+ g_amec->g44_avg[(i*MSA)+2] = (UINT32)g_amec->sys.todclock1.sample; // ptr to middle 16 bits of 48 bit TOD clock
+ g_amec->g44_avg[(i*MSA)+4] = (UINT32)g_amec->sys.todclock2.sample; // ptr to low 16 bits of 48 bit TOD clock
+
+ tempaccum=g_amec->sys.pwr250us.src_accum_snapshot; // load pwr250us accum from last 2msec
+ g_amec->sys.pwr250us.src_accum_snapshot = g_amec->sys.pwr250us.accumulator; // save current accum state for next 2msec
+ tempaccum=g_amec->sys.pwr250us.accumulator - tempaccum; // total accumulation over 2msec
+ tempaccum=tempaccum>>3; // divide by 8
+ g_amec->g44_avg[(i*MSA)+6] = g_amec->g44_avg[(i*MSA)+6] +
+ tempaccum;
+
+ tempaccum=g_amec->sys.pwr250usgpu.src_accum_snapshot; // load pwr250usgpu accum from last 2msec
+ g_amec->sys.pwr250usgpu.src_accum_snapshot = g_amec->sys.pwr250usgpu.accumulator; // save current accum state for next 2msec
+ tempaccum=g_amec->sys.pwr250usgpu.accumulator - tempaccum; // total accumulation over 2msec
+ tempaccum=tempaccum>>3; // divide by 8
+ g_amec->g44_avg[(i*MSA)+8] = g_amec->g44_avg[(i*MSA)+8] +
+ tempaccum;
+
+ tempaccum=g_amec->proc[i].pwr250us.src_accum_snapshot; // load accumulator from last 2msec
+ g_amec->proc[i].pwr250us.src_accum_snapshot = g_amec->proc[i].pwr250us.accumulator; // save current accum state for next 2msec
+ tempaccum=g_amec->proc[i].pwr250us.accumulator - tempaccum; // total accumulation over 2msec
+ tempaccum=tempaccum>>3; // divide by 8
+ g_amec->g44_avg[(i*MSA)+10] = g_amec->g44_avg[(i*MSA)+10] +
+ tempaccum;
+
+ tempaccum=g_amec->proc[i].pwr250usvdd.src_accum_snapshot; // load accumulator from last 2msec
+ g_amec->proc[i].pwr250usvdd.src_accum_snapshot = g_amec->proc[i].pwr250usvdd.accumulator; // save current accum state for next 2msec
+ tempaccum=g_amec->proc[i].pwr250usvdd.accumulator - tempaccum; // total accumulation over 2msec
+ tempaccum=tempaccum>>3;
+ g_amec->g44_avg[(i*MSA)+11] = g_amec->g44_avg[(i*MSA)+11] +
+ tempaccum;
+
+ tempaccum=g_amec->proc[i].vrm[0].volt250us.src_accum_snapshot; // load accumulator from last 2msec
+ g_amec->proc[i].vrm[0].volt250us.src_accum_snapshot = g_amec->proc[i].vrm[0].volt250us.accumulator; // save current accum state for next 2msec
+ tempaccum=g_amec->proc[i].vrm[0].volt250us.accumulator - tempaccum; // total accumulation over 2msec
+ temp32 = tempaccum<<3; // Pi, Vdd
+ tempreg = 4000;
+ // Convert voltage from 100uV resolution to 6.25mV resolution
+ tempreg = (UINT16)(UTIL_DIV32(temp32, tempreg));
+ g_amec->g44_avg[(i*MSA)+12] = g_amec->g44_avg[(i*MSA)+12] + (UINT32)tempreg;
+
+ tempaccum=g_amec->proc[i].vrm[1].volt250us.src_accum_snapshot; // load accumulator from last 2msec
+ g_amec->proc[i].vrm[1].volt250us.src_accum_snapshot = g_amec->proc[i].vrm[1].volt250us.accumulator; // save current accum state for next 2msec
+ tempaccum=g_amec->proc[i].vrm[1].volt250us.accumulator - tempaccum; // total accumulation over 2msec
+ temp32 = tempaccum<<3; // Pi, Vcs
+ tempreg = 4000;
+ // Convert voltage from 100uV resolution to 6.25mV resolution
+ tempreg = (UINT16)(UTIL_DIV32(temp32, tempreg));
+ g_amec->g44_avg[(i*MSA)+13] = g_amec->g44_avg[(i*MSA)+13] +
+ (UINT32)tempreg;
+
+ tempaccum=g_amec->proc[i].cur250usvdd.src_accum_snapshot; // load accumulator from last 2msec
+ g_amec->proc[i].cur250usvdd.src_accum_snapshot = g_amec->proc[i].cur250usvdd.accumulator; // save current accum state for next 2msec
+ tempaccum=g_amec->proc[i].cur250usvdd.accumulator - tempaccum; // total accumulation over 2msec
+ tempaccum=tempaccum>>3;
+ g_amec->g44_avg[(i*MSA)+14] = g_amec->g44_avg[(i*MSA)+14] +
+ tempaccum/100;
+ g_amec->g44_avg[(i*MSA)+15] = g_amec->g44_avg[(i*MSA)+15] +
+ (UINT32)g_amec->proc[i].temp2ms.sample; // hottest processor core temperature (average??)
+
+// major changes below to accommodate Group 45
+
+ l=16; // l = index offset
+ for (j=0; j<8; j++) // Group 45 supports all 8 Centaurs per OCC
+ {
+ g_amec->g44_avg[(i*MSA)+l] = g_amec->g44_avg[(i*MSA)+l] +
+ (UINT32)(g_amec->proc[i].memctl[j].mrd2ms.sample/78); // memory read bandwidth
+ l=l+1;
+ }
+ for (j=0; j<8; j++) // Group 45 supports all 8 Centaurs per OCC
+ {
+ g_amec->g44_avg[(i*MSA)+l] = g_amec->g44_avg[(i*MSA)+l] +
+ (UINT32)(g_amec->proc[i].memctl[j].mwr2ms.sample/78); // memory write bandwidth
+ l=l+1;
+ }
+
+ for (j=0; j<8; j++) // Group 45 supports all 8 L4 caches per OCC
+ {
+ temp16 = g_amec->proc[i].memctl[j].centaur.portpair[0].perf.l4rd2ms;
+ temp16 = temp16 + g_amec->proc[i].memctl[j].centaur.portpair[1].perf.l4rd2ms;
+ g_amec->g44_avg[(i*MSA)+l] = g_amec->g44_avg[(i*MSA)+l] +
+ (UINT32)(temp16/156); // L4 read bandwidth (/156 because two portpairs added together)
+ l=l+1;
+ }
+
+ for (j=0; j<8; j++) // Group 45 supports all 8 L4 caches per OCC
+ {
+ temp16 = g_amec->proc[i].memctl[j].centaur.portpair[0].perf.l4wr2ms;
+ temp16 = temp16 + g_amec->proc[i].memctl[j].centaur.portpair[1].perf.l4wr2ms;
+ g_amec->g44_avg[(i*MSA)+l] = g_amec->g44_avg[(i*MSA)+l] +
+ (UINT32)(temp16/156); // L4 write bandwidth (/156 because two portpairs added together)
+ l=l+1;
+ }
+
+ g_amec->g44_avg[(i*MSA)+48] = g_amec->g44_avg[(i*MSA)+48] +
+ (UINT32)(g_amec->proc[i].winkcnt2ms.sample<<3); // counter of cores that entered winkle for at least part of the 2msec interval: 1/8th resolution
+ g_amec->g44_avg[(i*MSA)+49] = g_amec->g44_avg[(i*MSA)+49] +
+ (UINT32)(g_amec->proc[i].sleepcnt2ms.sample<<3); // counter of cores that entered sleep for at least part of the 2msec interval: 1/8th resolution
+
+
+ m=0; // counter for actual configured # of cores - 1.
+ for (j=0; j<12; j++) // Group 45 supports up to 12 cores to be configured per OCC chip
+ {
+ if (CORE_PRESENT(j))
+ {
+ //average frequency for this core (apply rounding for frequency for maximum 8 bit resolution): 20MHz resolution (Power8 is actually 33.25MHz steps)
+ temp32 = (UINT32)g_amec->proc[i].core[j].freqa2ms.sample/10; // 10MHz resolution
+ temp16 = (UINT16)temp32;
+ temp32 = temp32 >>1; // convert to 20MHz resolution
+ if (temp16 & 1) temp32 = temp32+1; // if LSBit of 10MHz resolution value is a 1, then round the 20MHz resolution value up by 1
+
+ g_amec->g44_avg[(i*MSA)+50+m] = g_amec->g44_avg[(i*MSA)+50+m] + temp32;
+
+ m++; // increment configured core counter
+ if (m > 11) j=12; // safeguard in case more than 12 configured cores.
+ }
+ }
+
+ m=0; // counter for actual configured # of cores - 1.
+ for (j=0; j<12; j++) // Group 45 supports up to 12 cores to be configured per OCC chip
+ {
+ if (CORE_PRESENT(j))
+ {
+ tempreg = 0; // keeps track of maximum thread utilization for this core
+ temp32 = 0; // keeps track of average thread utilization for this core for non-zero threads (threadmode=0) or all threads (threadmode=1) or no average (threadmode=2)
+ temp16 = 0; // keeps track of non-zero threads
+ for (k=0; k < g_amec->analytics_threadcountmax; k++)
+ {
+ if (tempreg < g_amec->proc[i].core[j].thread[k].util2ms_thread)
+ {
+ tempreg = g_amec->proc[i].core[j].thread[k].util2ms_thread;
+ }
+ if ((0 < g_amec->proc[i].core[j].thread[k].util2ms_thread) ||
+ (g_amec->analytics_threadmode != 0))
+ {
+ // accumulate for computing average
+ temp32 = temp32 + g_amec->proc[i].core[j].thread[k].util2ms_thread;
+ // increment counter of threads
+ temp16 = temp16 + 1;
+ }
+ }
+ g_amec->g44_avg[(i*MSA)+62+m] = g_amec->g44_avg[(i*MSA)+62+m] +
+ (UINT32)(g_amec->proc[i].core[j].util2ms.sample/50); // accumulate util sensor that feeds IPS and DPS algorithms for this core
+
+ if (g_amec->analytics_threadmode == 2)
+ {
+ temp16 = tempreg; // Store maximum of all the threads on this core
+ }
+ if (g_amec->analytics_threadmode < 2)
+ {
+ if (temp16 > 0)
+ {
+ temp16 = (UINT16)(UTIL_DIV32(temp32, temp16)); // compute average utilization of all non-zero threads (threadmode=0) or all threads (threadmode=1)
+ }
+ }
+ if (g_amec->analytics_threadmode == 3)
+ {
+ // accumulate average finish latency counter for this core
+ temp16 = ((g_amec->proc[i].core[j].mcpifi2ms.sample) >>1);
+ }
+
+ temp32 = (UINT32)(temp16/25); // 0.25% utilization resolution
+ temp32 = temp32 >>1; // convert to 0.5% utilization resolution
+ if (temp16 & 1) temp32 = temp32+1; // if LSBit of 0.25% utilization resolution value is a 1, then round the 0.5% utilization resolution value up by 1
+ g_amec->g44_avg[(i * MSA) + 74 + m] = g_amec->g44_avg[(i * MSA) + 74 + m] +
+ (UINT32)(temp32); // accumulate average utilization or individual threads for this core or finish latency counter
+ g_amec->g44_avg[(i * MSA) + 86 + m] = g_amec->g44_avg[(i * MSA) + 86 + m] +
+ (UINT32)(g_amec->proc[i].core[j].ips2ms.sample / 50); // accumulate average MIPS for this core
+ g_amec->g44_avg[(i * MSA) + 98 + m] = g_amec->g44_avg[(i * MSA) + 98 + m] +
+ (UINT32)g_amec->proc[i].core[j].temp2ms.sample; // accumulate average temperature for this core
+ g_amec->g44_avg[(i * MSA) + 110 + m] = g_amec->g44_avg[(i * MSA) + 110 + m] +
+ (UINT32)((g_amec->proc[i].core[j].cmbw2ms.sample) / 156); // accumulate average memory bandwidth for this core //@mw713 /156, was /78 (overflow issues)
+ temp16 = ((g_amec->proc[i].core[j].mcpifd2ms.sample) / 100); // accumulate average busy latency counter for this core
+ g_amec->g44_avg[(i * MSA) + 122 + m] = g_amec->g44_avg[(i * MSA) + 122 + m] + (UINT32)temp16;
+ m++; // increment configured core counter
+ if (m > 11) j = 12; // safeguard in case more than 12 configured cores.
+ }
+ } // End loop processing each core
+ } // End loop processing each chip
+
+ // Determine when to update final analytics_array
+ temp16 = g_amec->r_cnt - g_amec->analytics_slot;
+ temp16 = ((1<<g_amec->stream_vector_rate)-1) & temp16;
+
+ // Have we completed this interval so that we can output?
+ if (temp16 == 0)
+ {
+ // Now, update Group 45 analytics packed array
+ switch (g_amec->analytics_thermal_offset)
+ {
+ case 0:
+ tempreg = (g_amec->sys.tempambient.sample) << 8; // upper byte
+ tempreg = tempreg | 0x8000; // Turn on MSBit for temporal frame sync
+ break;
+
+ case 1:
+ if (g_amec->mst_ips_parms.active == 0)
+ {
+ tempreg = 0; // If not in IPS mode, return 0
+ }
+ else
+ {
+ tempreg = 127; // If in IPS, return constant indicating in IPS mode
+ }
+ if (tempreg > 127) tempreg = 127; // Saturate at 7 bit limit (508 seconds)
+ tempreg = (tempreg) << 8; // upper byte
+ break;
+
+ case 2:
+ tempreg=(g_amec->mst_ips_parms.active)<<8; // upper byte
+ break;
+
+ case 3:
+ tempreg = (g_amec->fan.fanspeedavg.sample / 100) << 8; // upper byte (100 RPM resolution)
+ break;
+
+ case 4:
+ tempreg = (g_amec->proc[0].temp2msdimm.sample) << 8; // upper byte
+ break;
+
+ case 5:
+ tempreg = (g_amec->proc[0].temp2mscent.sample) << 8; // upper byte
+ break;
+
+ case 6:
+ // tempreg=(g_amec->proc[2].temp2msdimm.sample)<<8; // upper byte
+ tempreg = 0;
+ break;
+
+ case 7:
+ // tempreg=(g_amec->proc[2].temp2mscent.sample)<<8; // upper byte
+ tempreg = 0;
+ break;
+
+ default:
+ break;
+
+ }
+ g_amec->analytics_thermal_offset = 0x7 &
+ (g_amec->analytics_thermal_offset + 1); // modulo 8
+
+ tempaccum = g_amec->fan.pwr250usfan.src_accum_snapshot; // load accumulator from last 2msec
+ g_amec->fan.pwr250usfan.src_accum_snapshot = g_amec->fan.pwr250usfan.accumulator; // save current accum state for next 2msec
+ tempaccum = g_amec->fan.pwr250usfan.accumulator - tempaccum; // total accumulation over 2msec
+ tempaccum = tempaccum >> g_amec->stream_vector_rate;
+
+ tempreg = tempreg | (0xff & ((UINT16)tempaccum));
+ g_amec->analytics_array[5] = tempreg;
+
+ tempaccum = g_amec->io.pwr250usio.src_accum_snapshot; // load accumulator from last 2msec
+ g_amec->io.pwr250usio.src_accum_snapshot = g_amec->io.pwr250usio.accumulator; // save current accum state for next 2msec
+ tempaccum = g_amec->io.pwr250usio.accumulator - tempaccum; // total accumulation over 2msec
+ tempaccum = tempaccum >> g_amec->stream_vector_rate;
+
+ tempreg = ((UINT16)tempaccum) << 8; // upper byte
+
+ tempaccum = g_amec->storage.pwr250usstore.src_accum_snapshot; // load accumulator from last 2msec
+ g_amec->storage.pwr250usstore.src_accum_snapshot = g_amec->storage.pwr250usstore.accumulator; // save current accum state for next 2msec
+ tempaccum = g_amec->storage.pwr250usstore.accumulator - tempaccum; // total accumulation over 2msec
+ tempaccum = tempaccum >> g_amec->stream_vector_rate;
+
+ tempreg = tempreg | (0xff & ((UINT16)tempaccum));
+ g_amec->analytics_array[6] = tempreg;
+
+ tempaccum = g_amec->proc[0].pwr250usmem.src_accum_snapshot; // load accumulator from last 2msec
+ g_amec->proc[0].pwr250usmem.src_accum_snapshot = g_amec->proc[0].pwr250usmem.accumulator; // save current accum state for next 2msec
+ tempaccum = g_amec->proc[0].pwr250usmem.accumulator - tempaccum; // total accumulation over 2msec
+ tempaccum = tempaccum >> g_amec->stream_vector_rate;
+
+ tempreg = ((UINT16)tempaccum) << 8; // upper byte
+ g_amec->analytics_array[7] = tempreg;
+ g_amec->analytics_array[8] = 0;
+
+ // Now begins the per processor unique data
+ tempreg = (g_amec->analytics_total_chips) << 8; // upper byte
+ tempreg = tempreg | (0xff & (g_amec->analytics_chip)); // which chip is outputting this interval?
+ g_amec->analytics_array[9] = tempreg;
+ j = g_amec->analytics_chip; // select which chip to process
+
+ if (g_amec->analytics_option == 0)
+ {
+ k = 0; // Default to no shift, if user didn't enter analytics_total_chips (set to 0)
+ if (g_amec->analytics_total_chips == 1) k = g_amec->stream_vector_rate - 3; // (2msec * 2^k) is shift for averaging interval (16msec)
+ if (g_amec->analytics_total_chips == 2) k = g_amec->stream_vector_rate - 2; // (2msec * 2^k) is shift for averaging interval (32msec)
+ if (g_amec->analytics_total_chips == 4) k = g_amec->stream_vector_rate - 1; // (2msec * 2^k) is shift for averaging interval (64msec)
+ if (g_amec->analytics_total_chips == 8) k = g_amec->stream_vector_rate; // (2msec * 2^k) is shift for averaging interval (128msec)
+ }
+ if (g_amec->analytics_option == 1)
+ {
+ k = g_amec->stream_vector_rate - 3; // (2msec * 2^k) is shift for averaging interval (16msec)
+ }
+
+ l = 12; // index offset
+
+ g_amec->analytics_array[0] = (UINT16)g_amec->g44_avg[(j * MSA) + 0]; // todclock1 (hi 16 bits, no averaging)
+ g_amec->analytics_array[1] = (UINT16)g_amec->g44_avg[(j * MSA) + 2]; // todclock1 (medium 16 bits, no averaging)
+ g_amec->analytics_array[2] = (UINT16)g_amec->g44_avg[(j * MSA) + 4]; // todclock1 (lo 16 bits, no averaging)
+
+ g_amec->analytics_array[3] = (UINT16)(g_amec->g44_avg[(j * MSA) + 6] >> k); // the first two averages are 16 bits
+ g_amec->g44_avg[(j * MSA) + 6] = 0; // reset average for this sensor to 0
+ g_amec->analytics_array[4] = (UINT16)(g_amec->g44_avg[(j * MSA) + 8] >> k); // the first two averages are 16 bits
+ g_amec->g44_avg[(j * MSA) + 8] = 0; // reset average for this sensor to 0
+ g_amec->analytics_array[10] = (UINT16)(g_amec->g44_avg[(j * MSA) + 10] >> k); // the first two averages are 16 bits
+ g_amec->g44_avg[(j * MSA) + 10] = 0; // reset average for this sensor to 0
+ g_amec->analytics_array[11] = (UINT16)(g_amec->g44_avg[(j * MSA) + 11] >> k); // the first two averages are 16 bits
+ g_amec->g44_avg[(j * MSA) + 11] = 0; // reset average for this sensor to 0
+
+ for (i = 12; i <= 72; i++)
+ {
+ temp16 = (UINT16)(g_amec->g44_avg[(j * MSA) + l] >> k);
+ tempreg = temp16 << 8; // upper byte
+ temp16 = (UINT16)(g_amec->g44_avg[(j * MSA) + l + 1] >> k);
+ tempreg = tempreg | (0xff & temp16);
+ g_amec->analytics_array[i] = tempreg;
+ g_amec->g44_avg[(j * MSA) + l] = 0; // Reset average for this sensor to 0
+ g_amec->g44_avg[(j * MSA) + l + 1] = 0; // Reset average for this sensor to 0
+
+ l = l + 2;
+ }
+
+ // Final processing for Group 45: determine if cycling through all
+ // chips or just monitoring one chip
+ if (g_amec->analytics_option == 0)
+ {
+ g_amec->analytics_chip++;
+
+ if (g_amec->analytics_chip >= g_amec->analytics_total_chips)
+ {
+ g_amec->analytics_chip = 0; // loop back to chip 0 again
+ }
+ }
+
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_analytics.h b/src/occ_405/amec/amec_analytics.h
new file mode 100755
index 0000000..b6a344e
--- /dev/null
+++ b/src/occ_405/amec/amec_analytics.h
@@ -0,0 +1,47 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_analytics.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 _AMEC_ANALYTICS_H
+#define _AMEC_ANALYTICS_H
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Defines/Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Function Declarations */
+/*----------------------------------------------------------------------------*/
+
+// Function that enables stream buffer recording
+void amec_analytics_sb_recording(void);
+
+// Function that is called by AMEC State Machine for analytics
+void amec_analytics_main(void);
+
+#endif // _AMEC_ANALYTICS_H
diff --git a/src/occ_405/amec/amec_controller.c b/src/occ_405/amec/amec_controller.c
new file mode 100644
index 0000000..0b8b7e1
--- /dev/null
+++ b/src/occ_405/amec/amec_controller.c
@@ -0,0 +1,438 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_controller.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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <sensor.h>
+#include <amec_sys.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+extern uint8_t G_dimm_temp_expired_bitmap;
+extern uint8_t G_cent_temp_expired_bitmap;
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+// Function Specification
+//
+// Name: amec_controller_proc_thermal
+//
+// Description: This function implements the Proportional Controller for the
+// processor thermal control. Although it doesn't return any
+// results, it populates the thermal vote in the field
+// g_amec->thermalproc.speed_request.
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_controller_proc_thermal()
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_thermal_winner = 0;
+ uint16_t l_residue = 0;
+ uint16_t l_old_residue = 0;
+ int16_t l_error = 0;
+ int16_t l_cpu_speed = 0;
+ int16_t l_throttle_chg = 0;
+ int32_t l_throttle = 0;
+ sensor_t * l_sensor = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ // Get TEMP2MSP0PEAK sensor, which is hottest core temperature in OCC
+ // processor
+ l_sensor = getSensorByGsid(TEMP2MSP0PEAK);
+
+ // Use the highest temperature of all processors in 0.1 degrees C
+ l_thermal_winner = l_sensor->sample * 10;
+
+ // Check if there is an error
+ if (g_amec->thermalproc.setpoint == l_thermal_winner)
+ return;
+
+ // Calculate the thermal control error
+ l_error = g_amec->thermalproc.setpoint - l_thermal_winner;
+
+ // TODO: Get with Malcolm to migrate to 16-bit multiply
+ // Proportional Controller for the thermal control loop
+ l_throttle = (int32_t) l_error * g_amec->thermalproc.Pgain;
+ l_residue = (uint16_t) l_throttle;
+ l_throttle_chg = (int16_t) (l_throttle >> 16);
+
+ if ((int16_t) l_throttle_chg > (int16_t) g_amec->sys.speed_step_limit)
+ {
+ l_throttle_chg = g_amec->sys.speed_step_limit;
+ }
+ else
+ {
+ if ((int16_t) l_throttle_chg < ((int16_t) (-g_amec->sys.speed_step_limit)))
+ {
+ l_throttle_chg = (int16_t)(-g_amec->sys.speed_step_limit);
+ }
+ }
+
+ // Calculate the new thermal CPU speed request
+ l_cpu_speed = g_amec->thermalproc.speed_request +
+ (int16_t) l_throttle_chg * g_amec->sys.speed_step;
+
+ // Proceed with residue summation to correctly follow set-point
+ l_old_residue = g_amec->thermalproc.total_res;
+ g_amec->thermalproc.total_res += l_residue;
+ if (g_amec->thermalproc.total_res < l_old_residue)
+ {
+ l_cpu_speed += g_amec->sys.speed_step;
+ }
+
+ // Enforce actuator saturation limits
+ if (l_cpu_speed > g_amec->sys.max_speed)
+ l_cpu_speed = g_amec->sys.max_speed;
+ if (l_cpu_speed < g_amec->sys.min_speed)
+ l_cpu_speed = g_amec->sys.min_speed;
+
+ // Generate the new thermal speed request
+ g_amec->thermalproc.speed_request = l_cpu_speed;
+ // Calculate frequency request based on thermal speed request
+ g_amec->thermalproc.freq_request = amec_controller_speed2freq(
+ g_amec->thermalproc.speed_request,
+ g_amec->sys.fmax);
+}
+
+//*************************************************************************
+// Function Specification
+//
+// Name: amec_controller_dimm_thermal
+//
+// Description: This function implements the Proportional Controller for the
+// DIMM thermal control. Although it doesn't return any
+// results, it populates the thermal vote in the field
+// g_amec->thermaldimm.speed_request.
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_controller_dimm_thermal()
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_thermal_winner = 0;
+ uint16_t l_residue = 0;
+ uint16_t l_old_residue = 0;
+ int16_t l_error = 0;
+ int16_t l_mem_speed = 0;
+ int16_t l_throttle_chg = 0;
+ int32_t l_throttle = 0;
+ sensor_t * l_sensor = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ // Get TEMP2MSDIMM sensor value
+ l_sensor = getSensorByGsid(TEMP2MSDIMM);
+
+ if(G_dimm_temp_expired_bitmap)
+ {
+ //we were not able to read one or more dimm temperatures.
+ //Assume temperature is at the setpoint plus 1 degree C.
+ l_thermal_winner = g_amec->thermaldimm.setpoint + 10;
+ }
+ else
+ {
+ // Use the highest temperature of all DIMMs in 0.1 degrees C
+ l_thermal_winner = l_sensor->sample * 10;
+ }
+
+ // Check if there is an error
+ if (g_amec->thermaldimm.setpoint == l_thermal_winner)
+ return;
+
+ // Calculate the thermal control error
+ l_error = g_amec->thermaldimm.setpoint - l_thermal_winner;
+
+ // Proportional Controller for the thermal control loop based on DIMM
+ // temperatures
+ l_throttle = (int32_t) l_error * g_amec->thermaldimm.Pgain;
+ l_residue = (uint16_t) l_throttle;
+ l_throttle_chg = (int16_t) (l_throttle >> 16);
+
+ if ((int16_t) l_throttle_chg > AMEC_MEMORY_SPEED_CHANGE_LIMIT)
+ {
+ l_throttle_chg = AMEC_MEMORY_SPEED_CHANGE_LIMIT;
+ }
+ else
+ {
+ if ((int16_t) l_throttle_chg < (-AMEC_MEMORY_SPEED_CHANGE_LIMIT))
+ {
+ l_throttle_chg = -AMEC_MEMORY_SPEED_CHANGE_LIMIT;
+ }
+ }
+
+ // Calculate the new thermal speed request for DIMMs
+ l_mem_speed = g_amec->thermaldimm.speed_request +
+ (int16_t) l_throttle_chg * AMEC_MEMORY_STEP_SIZE;
+
+ // Proceed with residue summation to correctly follow set-point
+ l_old_residue = g_amec->thermaldimm.total_res;
+ g_amec->thermaldimm.total_res += l_residue;
+ if (g_amec->thermaldimm.total_res < l_old_residue)
+ {
+ l_mem_speed += AMEC_MEMORY_STEP_SIZE;
+ }
+
+ // Enforce actuator saturation limits
+ if (l_mem_speed > AMEC_MEMORY_MAX_STEP)
+ l_mem_speed = AMEC_MEMORY_MAX_STEP;
+ if (l_mem_speed < AMEC_MEMORY_MIN_STEP)
+ l_mem_speed = AMEC_MEMORY_MIN_STEP;
+
+ // Generate the new thermal speed request
+ g_amec->thermaldimm.speed_request = (uint16_t) l_mem_speed;
+}
+
+
+//*************************************************************************
+// Function Specification
+//
+// Name: amec_controller_centaur_thermal
+//
+// Description: This function implements the Proportional Controller for the
+// centaur thermal control. Although it doesn't return any
+// results, it populates the thermal vote in the field
+// g_amec->thermalcent.speed_request.
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_controller_centaur_thermal()
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_thermal_winner = 0;
+ uint16_t l_residue = 0;
+ uint16_t l_old_residue = 0;
+ int16_t l_error = 0;
+ int16_t l_mem_speed = 0;
+ int16_t l_throttle_chg = 0;
+ int32_t l_throttle = 0;
+ sensor_t * l_sensor = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ // Get TEMP2MSCENT sensor value
+ l_sensor = getSensorByGsid(TEMP2MSCENT);
+
+ if(G_cent_temp_expired_bitmap)
+ {
+ //we were not able to get a valid temperature. Assume it is 1 degree
+ //over the setpoint.
+ l_thermal_winner = g_amec->thermalcent.setpoint + 10;
+ }
+ else
+ {
+ // Use the highest temperature of all Centaur in 0.1 degrees C
+ l_thermal_winner = l_sensor->sample * 10;
+ }
+
+ // Check if there is an error
+ if (g_amec->thermalcent.setpoint == l_thermal_winner)
+ return;
+
+ // Calculate the thermal control error
+ l_error = g_amec->thermalcent.setpoint - l_thermal_winner;
+
+ // Proportional Controller for the thermal control loop based on CENTAUR
+ // temperatures
+ l_throttle = (int32_t) l_error * g_amec->thermalcent.Pgain;
+ l_residue = (uint16_t) l_throttle;
+ l_throttle_chg = (int16_t) (l_throttle >> 16);
+
+ if ((int16_t) l_throttle_chg > AMEC_MEMORY_SPEED_CHANGE_LIMIT)
+ {
+ l_throttle_chg = AMEC_MEMORY_SPEED_CHANGE_LIMIT;
+ }
+ else
+ {
+ if ((int16_t) l_throttle_chg < (-AMEC_MEMORY_SPEED_CHANGE_LIMIT))
+ {
+ l_throttle_chg = -AMEC_MEMORY_SPEED_CHANGE_LIMIT;
+ }
+ }
+
+ // Calculate the new thermal speed request for Centaurs
+ l_mem_speed = g_amec->thermalcent.speed_request +
+ (int16_t) l_throttle_chg * AMEC_MEMORY_STEP_SIZE;
+
+ // Proceed with residue summation to correctly follow set-point
+ l_old_residue = g_amec->thermalcent.total_res;
+ g_amec->thermalcent.total_res += l_residue;
+ if (g_amec->thermalcent.total_res < l_old_residue)
+ {
+ l_mem_speed += AMEC_MEMORY_STEP_SIZE;
+ }
+
+ // Enforce actuator saturation limits
+ if (l_mem_speed > AMEC_MEMORY_MAX_STEP)
+ l_mem_speed = AMEC_MEMORY_MAX_STEP;
+ if (l_mem_speed < AMEC_MEMORY_MIN_STEP)
+ l_mem_speed = AMEC_MEMORY_MIN_STEP;
+
+ // Generate the new thermal speed request
+ g_amec->thermalcent.speed_request = (uint16_t) l_mem_speed;
+}
+
+//*************************************************************************
+// Function Specification
+//
+// Name: amec_controller_vrhotproc
+//
+// Description: This function implements a Single-step Controller for the
+// processor VRHOT signal. Although it doesn't return any
+// results, it populates the frequency vote in the field
+// g_amec->vrhotproc.freq_request
+//
+//
+// End Function Specification
+void amec_controller_vrhotproc()
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ int16_t l_cpu_speed = 0;
+ int16_t l_throttle_chg = 0;
+ sensor_t *l_sensor = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ // Get VRHOT sensor, which is really a counter of consecutive times the
+ // VRHOT signal has been asserted
+ l_sensor = getSensorByGsid(VRHOT250USPROC);
+
+ // Single-step controller:
+ // If sensor VRHOT250USPROC is above the set-point, we need to step down.
+ // Else, do a single step up.
+ if (l_sensor->sample >= g_amec->vrhotproc.setpoint)
+ {
+ l_throttle_chg = (int16_t)(-1);
+ }
+ else
+ {
+ l_throttle_chg = (int16_t)(1);
+ }
+
+ // Calculate the new VRHOTPROC speed request
+ l_cpu_speed = g_amec->vrhotproc.speed_request +
+ (int16_t) l_throttle_chg * g_amec->sys.speed_step;
+
+ // Never allow negative speed requests
+ if (l_cpu_speed < 0)
+ {
+ l_cpu_speed = 0;
+ }
+
+ // Enforce actuator saturation limits
+ if (l_cpu_speed > g_amec->sys.max_speed)
+ {
+ l_cpu_speed = g_amec->sys.max_speed;
+ }
+ if (l_cpu_speed < g_amec->sys.min_speed)
+ {
+ l_cpu_speed = g_amec->sys.min_speed;
+ }
+
+ // Generate the new VRHOTPROC frequency request
+ g_amec->vrhotproc.speed_request = l_cpu_speed;
+ g_amec->vrhotproc.freq_request =
+ amec_controller_speed2freq(g_amec->vrhotproc.speed_request,
+ g_amec->sys.fmax);
+
+}
+
+//*************************************************************************
+// Function Specification
+//
+// Name: amec_controller_speed2freq
+//
+// Description: Helper function to convert speed to MHz.
+//
+// End Function Specification
+uint16_t amec_controller_speed2freq (const uint16_t i_speed, const uint16_t i_fmax)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_tempreg = 0;
+ uint16_t l_temp16 = 0;
+ uint32_t l_temp32 = 0;
+ uint16_t l_freq = 0;
+ uint32_t l_divide32[2] = {0, 0};
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ l_temp16 = i_fmax;
+ l_tempreg = (uint16_t)i_speed;
+ l_temp32 = ((uint32_t)l_tempreg)*((uint32_t)l_temp16);
+ l_temp16 = (uint16_t)1000;
+ l_divide32[1] = (uint32_t)l_temp16;
+ l_divide32[0] = (uint32_t)l_temp32;
+ l_divide32[0] /= l_divide32[1];
+ l_temp32 = l_divide32[0];
+ l_freq = (uint16_t)l_temp32; /* freq will always fit in 16 bits */
+
+ return l_freq;
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_controller.h b/src/occ_405/amec/amec_controller.h
new file mode 100644
index 0000000..8b2c1b9
--- /dev/null
+++ b/src/occ_405/amec/amec_controller.h
@@ -0,0 +1,132 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_controller.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 _AMEC_CONTROLLER_H
+#define _AMEC_CONTROLLER_H
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Globals */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Defines */
+/*----------------------------------------------------------------------------*/
+// Maximum speed supported for memory controllers (100.0%)
+#define AMEC_MEMORY_MAX_STEP 1000
+
+// Minimum speed supported for memory controllers (1.0%)
+#define AMEC_MEMORY_MIN_STEP 10
+
+// Step size for increasing or decreasing memory speed (1.0%)
+#define AMEC_MEMORY_STEP_SIZE 10
+
+// Limit value on speed change to avoid overflow of the controller
+#define AMEC_MEMORY_SPEED_CHANGE_LIMIT (UINT16_MAX/4)/AMEC_MEMORY_STEP_SIZE
+
+
+/*----------------------------------------------------------------------------*/
+/* Typedef / Enum */
+/*----------------------------------------------------------------------------*/
+///Controller Model
+typedef struct amec_controller
+{
+ ///Over-temperature error for FRU callout (in degrees C)
+ uint8_t ot_error;
+ ///Setpoint or reference for the controller
+ uint16_t setpoint;
+ ///Proportional gain of the controller
+ uint16_t Pgain;
+ ///Theoretical controller residue summation
+ uint16_t total_res;
+ ///Final speed request of the controller
+ uint16_t speed_request;
+ ///Final frequency request of the controller
+ uint16_t freq_request;
+ ///Expiration time for a temperature reading (in seconds)
+ uint8_t temp_timeout;
+}amec_controller_t;
+
+
+/*----------------------------------------------------------------------------*/
+/* Function Prototypes */
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Thermal Control Loop based on processor temperatures.
+ *
+ * This function implements the Proportional Controller for the thermal
+ * control loop. Although it doesn't return any results, it populates the
+ * thermal vote in the field g_amec->thermalproc.speed_request.
+ *
+ */
+void amec_controller_proc_thermal();
+
+/**
+ * Thermal Control Loop based on Centaur temperatures.
+ *
+ * This function implements a Proportional Controller for the
+ * thermal control loop based on Centaur temperatures.
+ * Although it doesn't return any results, it populates the
+ * thermal vote in the field g_amec->thermalcent.speed_request.
+ *
+ */
+void amec_controller_centaur_thermal();
+
+/**
+ * Thermal Control Loop based on DIMM temperatures.
+ *
+ * This function implements a Proportional Controller for the
+ * thermal control loop based on DIMM temperatures. Although it
+ * doesn't return any results, it populates the thermal vote in
+ * the field g_amec->thermaldimm.speed_request.
+ *
+ */
+void amec_controller_dimm_thermal();
+
+/**
+ * Helper function to convert speed to MHz
+ *
+ * This function converts a given speed in percentage (%) to a
+ * frequency in MHz.
+ *
+ */
+uint16_t amec_controller_speed2freq (const uint16_t i_speed, const uint16_t i_fmax);
+
+/**
+ * Thermal Control Loop based on VRHOT signal from processor
+ * regulators.
+ *
+ */
+void amec_controller_vrhotproc();
+
+
+#endif //_AMEC_CONTROLLER_H
diff --git a/src/occ_405/amec/amec_data.c b/src/occ_405/amec/amec_data.c
new file mode 100755
index 0000000..33142e1
--- /dev/null
+++ b/src/occ_405/amec/amec_data.c
@@ -0,0 +1,477 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include <errl.h>
+#include "sensor.h"
+#include "rtls.h"
+#include "occ_sys_config.h"
+#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE
+#include "dcom.h"
+#include "proc_data.h"
+#include "proc_data_control.h"
+#include "amec_smh.h"
+#include "amec_slave_smh.h"
+#include <trac.h>
+#include "amec_sys.h"
+#include "sensor_enum.h"
+#include "amec_service_codes.h"
+#include <amec_sensors_core.h>
+#include <amec_sensors_power.h>
+#include <amec_sensors_fw.h>
+#include <amec_data.h>
+#include <amec_freq.h>
+#include <thrm_thread.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+extern uint8_t G_occ_interrupt_type;
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+
+// Function Specification
+//
+// Name: AMEC_data_write_fcurr
+//
+// Description:
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+errlHndl_t AMEC_data_write_fcurr(const OCC_MODE i_mode)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ errlHndl_t l_err = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // If we're active we need to load this new range into DVFS MIN/MAX
+ if(CURRENT_STATE() == OCC_STATE_ACTIVE)
+ {
+ // Use i_mode here since this function understands turbo
+ l_err = amec_set_freq_range(i_mode);
+
+ if(l_err)
+ {
+ //break;
+ }
+ }
+
+ // If we are in OpenPower environment, load this new range into DVFS
+ // min/max for AMEC component
+ if(G_occ_interrupt_type != FSP_SUPPORTED_OCC)
+ {
+ g_amec->sys.fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
+ g_amec->sys.fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+
+ TRAC_INFO("AMEC_data_write_fcurr: New frequency range Fmin[%u] Fmax[%u]",
+ g_amec->sys.fmin,
+ g_amec->sys.fmax);
+ }
+
+ return l_err;
+}
+
+// Function Specification
+//
+// Name: AMEC_data_write_thrm_thresholds
+//
+// Description: This function loads data from the Thermal Control Threshold
+// data packet (format 0x13) into g_amec structure. This function should be
+// called when OCC goes active or changes modes or goes in/out of Acoustic
+// mode (ITE-only mode).
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+errlHndl_t AMEC_data_write_thrm_thresholds(const OCC_MODE i_mode)
+{
+
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ errlHndl_t l_err = NULL;
+ cmdh_thrm_thresholds_t *l_data = NULL;
+ cmdh_thrm_thresholds_set_t *l_frudata = NULL;
+ uint8_t l_dvfs_temp = 0;
+ uint8_t l_error = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ // Retrieve the thermal control threshold data
+ l_err = DATA_get_thrm_thresholds(&l_data);
+ if(l_err)
+ {
+ TRAC_ERR("AMEC_data_write_thrm_thresholds: Error retrieving thermal control threshold data");
+ break;
+ }
+
+ // Notify thermal thread to update its local copy of the thermal thresholds
+ THRM_thread_update_thresholds();
+
+ l_frudata = l_data->data;
+
+ // TODO: Need to check if acoustic mode has been enabled (ITE-only mode)
+
+ // Store the processor thermal data
+ if(i_mode == OCC_MODE_NOMINAL)
+ {
+ l_dvfs_temp = l_frudata[DATA_FRU_PROC].dvfs;
+ l_error = l_frudata[DATA_FRU_PROC].error;
+ }
+ else
+ {
+ l_dvfs_temp = l_frudata[DATA_FRU_PROC].pm_dvfs;
+ if(i_mode == OCC_MODE_TURBO)
+ {
+ //Need to log an error if we dvfs in static turbo mode (for mfg)
+ l_error = l_dvfs_temp;
+ }
+ else
+ {
+ l_error = l_frudata[DATA_FRU_PROC].pm_error;
+ }
+ }
+ // Store the DVFS thermal setpoint in 0.1 degrees C
+ g_amec->thermalproc.setpoint = l_dvfs_temp * 10;
+ // Store the error temperature for OT detection
+ g_amec->thermalproc.ot_error = l_error;
+ // Store the temperature timeout value
+ g_amec->thermalproc.temp_timeout = l_frudata[DATA_FRU_PROC].max_read_timeout;
+
+ TRAC_INFO("AMEC_data_write_thrm_thresholds: Setting %u as DVFS setpoint for processor",
+ l_dvfs_temp);
+
+ // Store the Centaur thermal data
+ if(i_mode == OCC_MODE_NOMINAL)
+ {
+ l_dvfs_temp = l_frudata[DATA_FRU_CENTAUR].dvfs;
+ l_error = l_frudata[DATA_FRU_CENTAUR].error;
+ }
+ else
+ {
+ l_dvfs_temp = l_frudata[DATA_FRU_CENTAUR].pm_dvfs;
+ if(i_mode == OCC_MODE_TURBO)
+ {
+ //Need to log an error if we throttle in static turbo mode (for mfg)
+ l_error = l_dvfs_temp;
+ }
+ else
+ {
+ l_error = l_frudata[DATA_FRU_CENTAUR].pm_error;
+ }
+ }
+
+ // Store the DVFS thermal setpoint in 0.1 degrees C
+ g_amec->thermalcent.setpoint = l_dvfs_temp * 10;
+ // Store the error temperature for OT detection
+ g_amec->thermalcent.ot_error = l_error;
+ // Store the temperature timeout value
+ g_amec->thermalcent.temp_timeout = l_frudata[DATA_FRU_CENTAUR].max_read_timeout;
+
+ TRAC_INFO("AMEC_data_write_thrm_thresholds: Setting %u as DVFS setpoint for Centaur",
+ l_dvfs_temp);
+
+ // Store the DIMM thermal data
+ if(i_mode == OCC_MODE_NOMINAL)
+ {
+ l_dvfs_temp = l_frudata[DATA_FRU_DIMM].dvfs;
+ l_error = l_frudata[DATA_FRU_DIMM].error;
+ }
+ else
+ {
+ l_dvfs_temp = l_frudata[DATA_FRU_DIMM].pm_dvfs;
+ if(i_mode == OCC_MODE_TURBO)
+ {
+ //Need to log an error if we throttle in static turbo mode (for mfg)
+ l_error = l_dvfs_temp;
+ }
+ else
+ {
+ l_error = l_frudata[DATA_FRU_DIMM].pm_error;
+ }
+ }
+ // Store the DVFS thermal setpoint in 0.1 degrees C
+ g_amec->thermaldimm.setpoint = l_dvfs_temp * 10;
+ // Store the error temperature for OT detection
+ g_amec->thermaldimm.ot_error = l_error;
+ // Store the temperature timeout value
+ g_amec->thermaldimm.temp_timeout = l_frudata[DATA_FRU_DIMM].max_read_timeout;
+
+ TRAC_INFO("AMEC_data_write_thrm_thresholds: Setting %u as DVFS setpoint for DIMM",
+ l_dvfs_temp);
+
+ // Store the VRM thermal data
+ g_amec->proc[0].vrfan_error_count = l_frudata[DATA_FRU_VRM].sample_error_count;
+ g_amec->vrhotproc.setpoint = l_frudata[DATA_FRU_VRM].error_count;
+
+ TRAC_INFO("AMEC_data_write_thrm_thresholds: Setting %u as DVFS setpoint for VRHOT",
+ g_amec->vrhotproc.setpoint);
+
+ } while(0);
+
+ return l_err;
+}
+
+// Function Specification
+//
+// Name: AMEC_data_write_ips_config
+//
+// Description: This function loads data from the IPS Config data packet
+// (format 0x11) into g_amec structure. This function should only by called by
+// Master OCC firmware.
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+errlHndl_t AMEC_data_write_ips_cnfg(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ errlHndl_t l_err = NULL;
+ cmdh_ips_config_data_t *l_data = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ // Retrieve the thermal control threshold data
+ l_err = DATA_get_ips_cnfg(&l_data);
+ if(l_err)
+ {
+ TRAC_ERR("AMEC_data_write_ips_cnfg: Error retrieving IPS config data");
+ break;
+ }
+
+ // Store Idle Power Saver settings for AMEC
+ // Delay times should be stored in number of samples
+ g_amec->mst_ips_parms.entry_delay = l_data->iv_delayTimeforEntry *
+ AMEC_DPS_SAMPLING_RATE;
+ g_amec->mst_ips_parms.exit_delay = l_data->iv_delayTimeforExit *
+ AMEC_DPS_SAMPLING_RATE;
+
+ // Utilization thresholds should be stored in hundredths of a percent
+ g_amec->mst_ips_parms.entry_threshold = l_data->iv_utilizationForEntry * 100;
+ g_amec->mst_ips_parms.exit_threshold = l_data->iv_utilizationForExit * 100;
+
+ // Enable/disable Idle Power Saver
+ g_amec->mst_ips_parms.enable = l_data->iv_ipsEnabled;
+
+ } while(0);
+
+ return l_err;
+}
+
+// Function Specification
+//
+// Name: AMEC_data_change
+//
+// Description:
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+errlHndl_t AMEC_data_change(const uint32_t i_data_mask)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ errlHndl_t l_err = NULL;
+ OCC_MODE l_cur_mode = OCC_MODE_NOCHANGE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ //l_cur_state = CURRENT_STATE();
+ l_cur_mode = CURRENT_MODE();
+
+ //If we received the frequency from TMGT
+ if(i_data_mask & DATA_MASK_FREQ_PRESENT)
+ {
+ l_err = AMEC_data_write_fcurr(l_cur_mode);
+ }
+ else if(i_data_mask & DATA_MASK_THRM_THRESHOLDS)
+ {
+ l_err = AMEC_data_write_thrm_thresholds(l_cur_mode);
+
+ if(l_err)
+ {
+ TRAC_ERR("AMEC_data_change: Error writing thermal threshold data!");
+ }
+ }
+ else if(i_data_mask & DATA_MASK_IPS_CNFG)
+ {
+ l_err = AMEC_data_write_ips_cnfg();
+
+ if(l_err)
+ {
+ TRAC_ERR("AMEC_data_change: Error writing IPS config data!");
+ }
+ }
+
+ return l_err;
+}
+
+// Function Specification
+//
+// Name: amec_data_write_pcap
+//
+// Description: Function called by slave interrupt handler to collect pcap
+// data sent by Master OCC.
+// If a new packet is received from Master, it will be written to
+// G_sysConfigData.pcap, and g_amec->pcap will be updated too.
+// Otherwise nothing happens.
+//
+// Thread: Interrupt Handler
+//
+// End Function Specification
+void amec_data_write_pcap(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ static uint8_t L_pcap_data_count = 0;
+ uint16_t l_customer = 0;
+ uint16_t l_system = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ //Check if Master sent a new packet of data.
+ if(L_pcap_data_count != G_dcom_slv_inbox_doorbell_rx.pcap.pcap_data_count)
+ {
+ //Update counter
+ L_pcap_data_count = G_dcom_slv_inbox_doorbell_rx.pcap.pcap_data_count;
+
+ //Copy pcap data received from Master OCC to G_sysConfigData
+ memcpy(&(G_sysConfigData.pcap),&(G_dcom_slv_inbox_doorbell_rx.pcap),
+ sizeof(pcap_config_data_t));
+
+ //Affects ITE ONLY: Check if it's ok (1) to exit the oversubscribed state
+ if(1 == G_sysConfigData.pcap.unthrottle)
+ {
+ //Clear throttle flag
+ g_amec->oversub_status.cmeThrottleLatchAmec = 0;
+ }
+
+ //Check node power cap requested by customer/system.
+ // 0 means there is no pcap for that parameter.
+ if(0 == G_sysConfigData.pcap.current_pcap)
+ {
+ l_customer = 0xFFFF;
+ }
+ else
+ {
+ l_customer = G_sysConfigData.pcap.current_pcap;
+ }
+
+ //Check fixed node power cap required by the system.
+ // 0 means there is no pcap for that parameter.
+ if(0 == G_sysConfigData.pcap.system_pcap)
+ {
+ l_system = 0xFFFF;
+ }
+ else
+ {
+ l_system = G_sysConfigData.pcap.system_pcap;
+ }
+
+ //Set the normal node pcap to the least of both system and customer pcap.
+ if(l_customer < l_system)
+ {
+ g_amec->pcap.norm_node_pcap = l_customer;
+ }
+ else
+ {
+ g_amec->pcap.norm_node_pcap = l_system;
+ }
+
+ ///////////////////////////////
+ //Set the oversubscription pcap
+ if(0 != G_sysConfigData.pcap.oversub_pcap)
+ {
+ g_amec->pcap.ovs_node_pcap = G_sysConfigData.pcap.oversub_pcap;
+ }
+ else
+ {
+ g_amec->pcap.ovs_node_pcap = G_sysConfigData.pcap.hard_min_pcap;
+ }
+
+ //Oversubscription pcap can NOT be higher than a customer set pcap.
+ if(g_amec->pcap.ovs_node_pcap > l_customer)
+ {
+ g_amec->pcap.ovs_node_pcap = l_customer;
+ }
+
+ // update data mask notifying we got pcap information
+ extern data_cnfg_t * G_data_cnfg;
+ G_data_cnfg->data_mask |= DATA_MASK_PCAP_PRESENT;
+ TRAC_IMP("amec_data_write: PCAP Config data: pcap[%d]: data_mask[%x]", g_amec->pcap.norm_node_pcap, G_data_cnfg->data_mask);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_data.h b/src/occ_405/amec/amec_data.h
new file mode 100755
index 0000000..ee7fccf
--- /dev/null
+++ b/src/occ_405/amec/amec_data.h
@@ -0,0 +1,82 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_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 _AMEC_DATA_H
+#define _AMEC_DATA_H
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include <ssx_app_cfg.h>
+#include <amec_smh.h>
+#include <errl.h>
+#include <mode.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// This is used to change the current Freq data AMEC is using
+errlHndl_t AMEC_data_write_fcurr(const OCC_MODE i_mode);
+
+// This is used to store the thermal thresholds AMEC is using
+errlHndl_t AMEC_data_write_thrm_thresholds(const OCC_MODE i_mode);
+
+// This is used to store the IPS config data AMEC is using
+errlHndl_t AMEC_data_write_ips_cnfg(void);
+
+// This is used to notify AMEC that there is a change to the configuration data
+errlHndl_t AMEC_data_change(const uint32_t i_data_mask);
+
+// Writes pcap data sent by master to slave accessable structure.
+void amec_data_write_pcap();
+
+#endif
diff --git a/src/occ_405/amec/amec_dps.c b/src/occ_405/amec/amec_dps.c
new file mode 100755
index 0000000..ac6aff7
--- /dev/null
+++ b/src/occ_405/amec/amec_dps.c
@@ -0,0 +1,365 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_dps.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 */
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+#include <common_types.h>
+#include <occ_sys_config.h>
+#include <proc_data.h>
+#include <amec_sys.h>
+#include <amec_perfcount.h>
+#include <amec_part.h>
+#include <amec_dps.h>
+#include <sensor.h>
+#include <amec_controller.h>
+
+/*----------------------------------------------------------------------------*/
+/* Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Globals */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Typedef / Enum */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Internal Function Prototypes */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Code */
+/*----------------------------------------------------------------------------*/
+
+// Function Specification
+//
+// Name: amec_dps_update_core_util
+//
+// Description: Update per-core utilization variables.
+//
+// End Function Specification
+void amec_dps_update_core_util(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_temp16 = 0;
+ uint8_t l_tempreg = 0;
+ uint8_t l_idx = 0;
+ amec_core_perf_counter_t* l_perf = NULL;
+ amec_part_t *l_part = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // If g_amec->fw.dps_no_update_flag=1, no updating is allowed
+ if (!g_amec->fw.dps_no_update_flag)
+ {
+ // Update moving average of util_slack and util_active for all cores
+ for(l_idx=0; l_idx<MAX_NUM_CORES; l_idx++)
+ {
+ if (!CORE_PRESENT(l_idx))
+ {
+ continue; //nothing to do if the core's disabled
+ }
+
+ l_part = amec_part_find_by_core(&g_amec->part_config, l_idx);
+
+ // If this core doesn't belong to a core group, then do nothing
+ if (l_part == NULL)
+ {
+ continue;
+ }
+
+ // Get pointer to the perf struc of this core
+ l_perf = &g_amec->proc[0].core[l_idx].core_perf;
+
+ l_perf->ptr_putUtilslack--; // Decrement put pointer
+ if (l_perf->ptr_putUtilslack > TWO_TO_THE_POWER_OF_FIFTEEN)
+ {
+ // Wrap circular pointer. WARNING -> buffer size must be a
+ // power of 2
+ l_perf->ptr_putUtilslack &= (MAX_UTIL_SLACK_AVG_LEN-1);
+ }
+
+ // Locate oldest sample associated with 32-bit moving average
+ // WARNING -> we need to read this sample first in case entire
+ // buffer is used which would result in the write overwriting the
+ // oldest sample we need to read.
+ l_temp16=(uint16_t)(l_perf->ptr_putUtilslack+l_part->dpsalg.sample_count_util) & (MAX_UTIL_SLACK_AVG_LEN-1);
+ l_tempreg=l_perf->ptr_util_slack_avg_buffer[l_temp16];
+ // Bleed off oldest sample from moving average
+ l_perf->util_slack_accumulator = l_perf->util_slack_accumulator-(uint32_t)l_tempreg;
+ l_tempreg=l_perf->ptr_util_active_avg_buffer[l_temp16];
+ // Bleed off oldest sample from moving average
+ l_perf->util_active_accumulator = l_perf->util_active_accumulator-(uint32_t)l_tempreg;
+ // Add in newest sample into moving average
+ l_tempreg = l_perf->util_slack_core_counter;
+ l_perf->util_slack_accumulator = l_perf->util_slack_accumulator+(uint32_t)l_tempreg;
+ // Write new sample into buffer.
+ l_perf->ptr_util_slack_avg_buffer[l_perf->ptr_putUtilslack]=l_tempreg;
+ // Add in newest sample into moving average
+ l_tempreg = l_perf->util_active_core_counter;
+ l_perf->util_active_accumulator = l_perf->util_active_accumulator+(uint32_t)l_tempreg;
+ // Write new sample into buffer.
+ l_perf->ptr_util_active_avg_buffer[l_perf->ptr_putUtilslack]=l_tempreg;
+
+ // Reset counters every 2msec
+ l_perf->util_active_core_counter=0;
+ l_perf->util_slack_core_counter=0;
+ }
+ }
+}
+
+// Function Specification
+//
+// Name: amec_dps_partition_update_sensors
+//
+// Description: Update utilization sensors for a core group.
+//
+// End Function Specification
+void amec_dps_partition_update_sensors(const uint16_t i_part_id)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ amec_core_perf_counter_t* l_perf = NULL;
+ uint16_t l_core_index = 0;
+ uint8_t l_idx = 0;
+ uint32_t l_cg_active_accumulator = 0;
+ uint32_t l_cg_slack_accumulator = 0;
+ uint16_t l_cg_util_slack_perc = 0;
+ uint32_t l_divide32[2] = {0, 0};
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ for (l_idx=0; l_idx<g_amec->part_config.part_list[i_part_id].ncores; l_idx++)
+ {
+ l_core_index = g_amec->part_config.part_list[i_part_id].core_list[l_idx];
+ l_perf = &g_amec->proc[0].core[l_core_index % MAX_NUM_CORES].core_perf;
+
+ // Sum accumulators for core group
+ l_cg_active_accumulator += l_perf->util_active_accumulator;
+ l_cg_slack_accumulator += l_perf->util_slack_accumulator;
+ }
+
+ if (l_cg_active_accumulator == 0)
+ {
+ // Check for divide by zero
+ l_cg_util_slack_perc=16384; // if no active cores, set slack=100%
+ }
+ else
+ {
+ l_divide32[1]=(uint32_t)l_cg_active_accumulator;
+ l_divide32[0]=(uint32_t)l_cg_slack_accumulator<<14; // *16384 because 16384=1.0
+ l_divide32[0] /= l_divide32[1];
+ l_cg_util_slack_perc=(uint16_t)(l_divide32[0]);
+ }
+
+ // Update the sensor of the utilization slack
+ sensor_update(&g_amec->part_config.part_list[i_part_id].util2msslack, l_cg_util_slack_perc);
+}
+
+// Function Specification
+//
+// Name: amec_dps_partition_alg
+//
+// Description: DPS algorithm function.
+//
+// End Function Specification
+void amec_dps_partition_alg(const uint16_t i_part_id)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ amec_core_perf_counter_t* l_perf = NULL;
+ uint16_t l_freq = 0;
+ uint16_t l_core_index = 0;
+ uint16_t l_idx = 0;
+ uint16_t l_tempreg = 0;
+ uint16_t l_temp16 = 0;
+ uint32_t l_divide32[2] = {0, 0};
+ OCC_INTERNAL_MODE l_part_policy = 0xFF;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Switch on dps_type of the core group
+ switch (g_amec->part_config.part_list[i_part_id].dpsalg.type)
+ {
+ case 0x00:
+ // Type 0 algorithm: no dynamic power savings enabled
+ for (l_idx=0; l_idx<g_amec->part_config.part_list[i_part_id].ncores; l_idx++)
+ {
+ l_core_index = g_amec->part_config.part_list[i_part_id].core_list[l_idx];
+ l_perf = &g_amec->proc[0].core[l_core_index % MAX_NUM_CORES].core_perf;
+ l_perf->dps_freq_request = UINT16_MAX;
+ }
+ break;
+
+ case 41:
+ // Type 41 algorithm
+ // l_tempreg=measure of slack over gamma time interval on a per core basis
+ l_tempreg = (uint16_t)g_amec->part_config.part_list[i_part_id].util2msslack.sample;
+ // Convert to 10000 is equivalent to 100.00% utilization.
+ l_divide32[1]=(uint32_t)53687;
+ l_divide32[0]=(uint32_t)l_tempreg<<15;
+ l_divide32[0] /= l_divide32[1];
+ // l_tempreg is level of utilization using per core info
+ l_tempreg=10000-(uint16_t)(l_divide32[0]);
+
+ l_temp16 = g_amec->part_config.part_list[i_part_id].dpsalg.util_speed_request;
+ if (l_tempreg > g_amec->part_config.part_list[i_part_id].dpsalg.alpha_up)
+ {
+ l_temp16 = g_amec->part_config.part_list[i_part_id].dpsalg.util_speed_request +
+ g_amec->part_config.part_list[i_part_id].dpsalg.step_up;
+ }
+ else
+ {
+ if (l_tempreg < g_amec->part_config.part_list[i_part_id].dpsalg.alpha_down)
+ {
+ l_temp16 = g_amec->part_config.part_list[i_part_id].dpsalg.util_speed_request -
+ g_amec->part_config.part_list[i_part_id].dpsalg.step_down;
+ }
+ }
+
+ // Now limit final speed in l_temp16 to be between allowed speeds.
+ if (l_temp16 > g_amec->sys.max_speed)
+ {
+ l_temp16 = g_amec->sys.max_speed;
+ }
+ // Use the lower boundary based on the power policy of the core group
+ l_part_policy = g_amec->part_config.part_list[i_part_id].es_policy;
+ if (l_temp16 < g_amec->part_mode_freq[l_part_policy].min_speed)
+ {
+ l_temp16 = g_amec->part_mode_freq[l_part_policy].min_speed;
+ }
+
+ // Generate vote for utilization
+ g_amec->part_config.part_list[i_part_id].dpsalg.util_speed_request = l_temp16;
+ l_freq = amec_controller_speed2freq(l_temp16, g_amec->part_mode_freq[l_part_policy].fmax);
+ g_amec->part_config.part_list[i_part_id].dpsalg.freq_request = l_freq;
+
+ for (l_idx=0; l_idx<g_amec->part_config.part_list[i_part_id].ncores; l_idx++)
+ {
+ l_core_index = g_amec->part_config.part_list[i_part_id].core_list[l_idx];
+ l_perf = &g_amec->proc[0].core[l_core_index % MAX_NUM_CORES].core_perf;
+ l_perf->dps_freq_request = l_freq;
+ }
+ // End algorithm type 41
+ break;
+
+ default:
+ break;
+ }
+}
+
+// Function Specification
+//
+// Name: amec_dps_main
+//
+// Description: Main DPS function.
+//
+// End Function Specification
+void amec_dps_main(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_idx = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // First, update the utilization variables for all cores
+ amec_dps_update_core_util();
+
+ // Loop through all core groups and apply energy-savings policy
+ for (l_idx=0; l_idx<AMEC_PART_MAX_PART; l_idx++)
+ {
+ if (!g_amec->part_config.part_list[l_idx].valid)
+ {
+ continue;
+ }
+
+ if (g_amec->part_config.part_list[l_idx].ncores == 0)
+ {
+ continue;
+ }
+
+ switch (g_amec->part_config.part_list[l_idx].es_policy)
+ {
+ case OCC_INTERNAL_MODE_DPS:
+ case OCC_INTERNAL_MODE_DPS_MP:
+ amec_dps_partition_update_sensors(l_idx);
+ amec_dps_partition_alg(l_idx);
+ break;
+
+ default:
+ // No energy-savings policy: DPS vote is already disabled when
+ // policy first selected for partition or core ownership
+ // changes (amec_part.c)
+ break;
+ }
+ }
+
+ // For GA1, we need to send the Fwish to the Master OCC
+ if ((g_amec->part_config.part_list[0].es_policy == OCC_INTERNAL_MODE_DPS) ||
+ (g_amec->part_config.part_list[0].es_policy == OCC_INTERNAL_MODE_DPS_MP))
+ {
+ // If this core group policy is one of the DPS modes, then send the
+ // frequency request from the DPS algorithm
+ G_dcom_slv_outbox_tx.fwish =
+ g_amec->part_config.part_list[0].dpsalg.freq_request;
+ }
+ else
+ {
+ // Else, send the nominal frequency of the system
+ G_dcom_slv_outbox_tx.fwish =
+ g_amec->part_mode_freq[OCC_INTERNAL_MODE_NOM].fmax;
+ }
+ // We also need to send the Factual to the Master OCC
+ for (l_idx=0; l_idx<MAX_NUM_CORES; l_idx++)
+ {
+ // Find the first valid core and send its frequency
+ if (CORE_PRESENT(l_idx))
+ {
+ G_dcom_slv_outbox_tx.factual =
+ AMECSENSOR_ARRAY_PTR(FREQ250USP0C0,l_idx)->sample;
+ break;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_dps.h b/src/occ_405/amec/amec_dps.h
new file mode 100755
index 0000000..c342139
--- /dev/null
+++ b/src/occ_405/amec/amec_dps.h
@@ -0,0 +1,114 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_dps.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 _AMEC_DPS_H
+#define _AMEC_DPS_H
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Globals */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Defines */
+/*----------------------------------------------------------------------------*/
+#define TWO_TO_THE_POWER_OF_FIFTEEN 32768
+
+/*----------------------------------------------------------------------------*/
+/* Typedef / Enum */
+/*----------------------------------------------------------------------------*/
+///DPS Algorithm Model
+typedef struct amec_dps
+{
+ ///Frequency request for core voting box
+ uint16_t freq_request;
+ ///Utilization speed request
+ uint16_t util_speed_request;
+ ///Utilization threshold for moving down in frequency (low side)
+ uint16_t tlutil;
+ ///Step size for going up in speed
+ uint16_t step_up;
+ ///Step size for going down in speed
+ uint16_t step_down;
+ ///Number of utilization samples in sliding window
+ uint16_t sample_count_util;
+ ///Epsilon used for determining if a core is active (units of 0.01%)
+ uint16_t epsilon_perc;
+ ///Threshold for going up in frequency
+ uint16_t alpha_up;
+ ///Threshold for going down in frequency
+ uint16_t alpha_down;
+ ///8-bit mask for dynamic power save type (=0:none active)
+ uint8_t type;
+}amec_dps_t;
+
+/*----------------------------------------------------------------------------*/
+/* Function Prototypes */
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Update per-core utilization variables.
+ *
+ * This function updates all the per-core utilization variables. These
+ * variables are used to populate the slack sensors.
+ *
+ */
+void amec_dps_update_core_util(void);
+
+/**
+ * Update utilization sensors for a core group.
+ *
+ * This function updates the utilization (slack) sensors for a
+ * given core group.
+ *
+ */
+void amec_dps_partition_update_sensors(const uint16_t i_part_id);
+
+/**
+ * DPS algorithm function.
+ *
+ * This function implements the different DPS algorithms for a
+ * given core group.
+ *
+ */
+void amec_dps_partition_alg(const uint16_t i_part_id);
+
+/**
+ * Main DPS function.
+ *
+ * This function is the entry-point for running DPS algorithms
+ * and is aware of the different core groups defined.
+ *
+ */
+void amec_dps_main(void);
+
+#endif /* #ifndef _AMEC_DPS_H */
diff --git a/src/occ_405/amec/amec_external.h b/src/occ_405/amec/amec_external.h
new file mode 100755
index 0000000..17fcd57
--- /dev/null
+++ b/src/occ_405/amec/amec_external.h
@@ -0,0 +1,69 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_external.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 _AMEC_EXTERNAL_H
+#define _AMEC_EXTERNAL_H
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include <ssx_app_cfg.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+// task for amec master code
+void task_amec_master( task_t *i_self);
+
+// task for amec slave code
+void task_amec_slave( task_t *i_self);
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+#endif //_AMEC_EXTERNAL_H
diff --git a/src/occ_405/amec/amec_freq.c b/src/occ_405/amec/amec_freq.c
new file mode 100755
index 0000000..953bf27
--- /dev/null
+++ b/src/occ_405/amec/amec_freq.c
@@ -0,0 +1,1069 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_freq.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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include <errl.h>
+#include "sensor.h"
+#include "rtls.h"
+#include "occ_sys_config.h"
+#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE
+#include "dcom.h"
+#include "proc_data.h"
+#include "proc_data_control.h"
+#include "amec_smh.h"
+#include "amec_slave_smh.h"
+#include <trac.h>
+#include "amec_sys.h"
+#include "sensor_enum.h"
+#include "amec_service_codes.h"
+#include <amec_sensors_core.h>
+#include <amec_sensors_power.h>
+#include <amec_sensors_fw.h>
+#include <amec_data.h>
+#include <amec_freq.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+extern uint8_t G_cent_temp_expired_bitmap;
+extern uint8_t G_dimm_temp_expired_bitmap;
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+BOOLEAN G_non_dps_power_limited = FALSE;
+uint8_t G_amec_kvm_throt_reason = NO_THROTTLE;
+uint16_t G_time_until_freq_check = FREQ_CHG_CHECK_TIME;
+
+//FFDC SCOM addresses as requested by Greg Still in defect SW247927
+//If new SCOM addresses are added, update the size of the array.
+const uint32_t G_pmc_ffdc_scom_addrs[PMC_FFDC_SCOM_ADDRS_SIZE] =
+{
+ PMC_LFIR_ERR_REG,
+ PMC_LFIR_ERR_MASK_REG,
+ OCB_OCCLFIR,
+ PBA_FIR,
+ TOD_VALUE_REG
+};
+
+//FFDC OCI addresses as requested by Greg Still in defect SW247927
+//If new OCI addresses are added, update the size of the array.
+const uint32_t G_pmc_ffdc_oci_addrs[PMC_FFDC_OCI_ADDRS_SIZE] =
+{
+ PMC_MODE_REG,
+ PMC_PSTATE_MONITOR_AND_CTRL_REG,
+ PMC_RAIL_BOUNDS_REGISTER,
+ PMC_PARAMETER_REG0,
+ PMC_PARAMETER_REG1,
+ PMC_EFF_GLOBAL_ACTUAL_VOLTAGE_REG,
+ PMC_STATUS_REG,
+ PMC_INTCHP_CTRL_REG1,
+ PMC_INTCHP_CTRL_REG4,
+ PMC_INTCHP_STATUS_REG,
+ PMC_INTCHP_COMMAND_REG,
+ PMC_INTCHP_PSTATE_REG,
+ PMC_SPIV_CTRL_REG0A,
+ PMC_SPIV_CTRL_REG0B,
+ PMC_SPIV_CTRL_REG1,
+ PMC_SPIV_CTRL_REG2,
+ PMC_SPIV_CTRL_REG3,
+ PMC_SPIV_CTRL_REG4,
+ PMC_SPIV_STATUS_REG,
+ PMC_SPIV_COMMAND_REG,
+ PMC_O2S_CTRL_REG0A,
+ PMC_O2S_CTRL_REG0B,
+ PMC_O2S_CTRL_REG1,
+ PMC_O2S_CTRL_REG2,
+ PMC_O2S_CTRL_REG4,
+ PMC_O2S_STATUS_REG,
+ PMC_O2S_COMMAND_REG,
+ PMC_O2S_WDATA_REG,
+ PMC_CORE_DECONFIGURATION_REG,
+ PMC_FSMSTATE_STATUS_REG,
+ PMC_GPSA_ACK_COLLECTION_REG,
+ PMC_GPSA_ACK_COLLECTION_MASK_REG,
+ PMC_OCC_HEARTBEAT_REG,
+ 0 //0 marks last OCI address
+};
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+
+// Function Specification
+//
+// Name: amec_set_freq_range
+//
+// Description: Set the frequency range for AMEC
+// This function will run on mode changes and cnfg_data changes
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+errlHndl_t amec_set_freq_range(const OCC_MODE i_mode)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ errlHndl_t l_err = NULL;
+ uint16_t l_freq_min = 0;
+ uint16_t l_freq_max = 0;
+ uint32_t l_temp = 0;
+ amec_mode_freq_t l_ppm_freq[OCC_INTERNAL_MODE_MAX_NUM] = {{0}};
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // First set to Max Freq Range for this mode
+ if( VALID_MODE(i_mode) )
+ {
+ l_freq_min = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+ l_freq_max = G_sysConfigData.sys_mode_freq.table[i_mode];
+ }
+
+ // If SMS is set then TMGT wants us to pin to frequency which
+ // corresponds to input mode. They will use this function
+ // when powering off and they wish to have us bring the system
+ // back up to real nominal frequency (without being impacted
+ // by power caps or thermal actuations)
+ if(CURRENT_SMS() == SMGR_SMS_STATIC_VF_CHANGE_REQ)
+ {
+ l_freq_min = l_freq_max;
+ }
+
+ g_amec->sys.fmin = l_freq_min;
+ g_amec->sys.fmax = l_freq_max;
+
+ TRAC_INFO("amec_set_freq_range: Mode[0x%02x] Fmin[%u] Fmax[%u]",
+ i_mode,
+ l_freq_min,
+ l_freq_max);
+
+ // Now determine the max frequency for the PPM structure
+ l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL];
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_DYN_POWER_SAVE];
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_DYN_POWER_SAVE_FP];
+
+ // Determine the min frequency for the PPM structure. This Fmin should
+ // always be set to the system Fmin
+ l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+
+ // Determine the min speed allowed for DPS power policies (this is needed
+ // by the DPS algorithms)
+ l_temp = (l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmin * 1000)/l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax;
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS].min_speed = l_temp;
+
+ l_temp = (l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmin * 1000)/l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmax;
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].min_speed = l_temp;
+
+ // Copy the PPM frequency information into g_amec
+ memcpy(g_amec->part_mode_freq, l_ppm_freq, sizeof(l_ppm_freq));
+
+ TRAC_INFO("amec_set_freq_range: PPM Fmin[%u] Fnom[%u] Fmax[%u] min_speed[%u]",
+ l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmin,
+ l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmax,
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax,
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].min_speed);
+
+ return l_err;
+}
+
+// Function Specification
+//
+// Name: amec_slv_voting_box
+//
+// Description: Slave OCC's voting box that decides the frequency request.
+// This function will run every tick.
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_slv_voting_box(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t k = 0;
+ uint16_t l_chip_fmax = g_amec->sys.fmax;
+ uint16_t l_core_freq = 0;
+ uint32_t l_chip_reason = 0;
+ uint32_t l_core_reason = 0;
+ uint8_t l_kvm_throt_reason = NO_THROTTLE;
+ amec_part_t *l_part = NULL;
+ bool l_freq_req_changed = FALSE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Voting Box for CPU speed.
+ // This function implements the voting box to decide which input gets the right
+ // to actuate the system.
+
+ //Reset the maximum core frequency requested prior to recalculation.
+ g_amec->proc[0].core_max_freq = 0;
+
+ // PPB_FMAX
+ if(g_amec->proc[0].pwr_votes.ppb_fmax < l_chip_fmax)
+ {
+ l_chip_fmax = g_amec->proc[0].pwr_votes.ppb_fmax;
+ l_chip_reason = AMEC_VOTING_REASON_PPB;
+ l_kvm_throt_reason = POWERCAP;
+ }
+
+ // PMAX_CLIP_FREQ
+ if(g_amec->proc[0].pwr_votes.pmax_clip_freq < l_chip_fmax)
+ {
+ l_chip_fmax = g_amec->proc[0].pwr_votes.pmax_clip_freq;
+ l_chip_reason = AMEC_VOTING_REASON_PMAX;
+ l_kvm_throt_reason = POWER_SUPPLY_FAILURE;
+ }
+
+ // Pmax_clip frequency request if there is an APSS failure
+ if(g_amec->proc[0].pwr_votes.apss_pmax_clip_freq < l_chip_fmax)
+ {
+ l_chip_fmax = g_amec->proc[0].pwr_votes.apss_pmax_clip_freq;
+ l_chip_reason = AMEC_VOTING_REASON_APSS_PMAX;
+ l_kvm_throt_reason = POWER_SUPPLY_FAILURE;
+ }
+
+ //THERMALPROC.FREQ_REQUEST
+ //Thermal controller input based on processor temperature
+ if(g_amec->thermalproc.freq_request < l_chip_fmax)
+ {
+ l_chip_fmax = g_amec->thermalproc.freq_request;
+ l_chip_reason = AMEC_VOTING_REASON_PROC_THRM;
+ l_kvm_throt_reason = CPU_OVERTEMP;
+ }
+
+ // Controller request based on VRHOT signal from processor regulator
+ if(g_amec->vrhotproc.freq_request < l_chip_fmax)
+ {
+ l_chip_fmax = g_amec->vrhotproc.freq_request;
+ l_chip_reason = AMEC_VOTING_REASON_VRHOT_THRM;
+ l_kvm_throt_reason = CPU_OVERTEMP;
+ }
+
+ // CONN_OC_VOTE
+ if(g_amec->proc[0].pwr_votes.conn_oc_vote < l_chip_fmax)
+ {
+ l_chip_fmax = g_amec->proc[0].pwr_votes.conn_oc_vote;
+ l_chip_reason = AMEC_VOTING_REASON_CONN_OC;
+ l_kvm_throt_reason = OVERCURRENT;
+ }
+
+ for (k=0; k<MAX_NUM_CORES; k++)
+ {
+ if(CORE_PRESENT(k))
+ {
+ l_core_freq = l_chip_fmax;
+ l_core_reason = l_chip_reason;
+
+ // Disable DPS in KVM
+ if(!G_sysConfigData.system_type.kvm)
+ {
+ l_part = amec_part_find_by_core(&g_amec->part_config, k);
+
+ // Check frequency request generated by DPS algorithms
+ if(g_amec->proc[0].core[k].core_perf.dps_freq_request < l_core_freq)
+ {
+ l_core_freq = g_amec->proc[0].core[k].core_perf.dps_freq_request;
+ l_core_reason = AMEC_VOTING_REASON_UTIL;
+ }
+
+ // Adjust frequency based on soft frequency boundaries
+ if(l_part != NULL)
+ {
+ if(l_core_freq < l_part->soft_fmin)
+ {
+ // Before enforcing a soft Fmin, make sure we don't
+ // have a thermal or power emergency
+ if(!(l_chip_reason & (AMEC_VOTING_REASON_PROC_THRM |
+ AMEC_VOTING_REASON_VRHOT_THRM |
+ AMEC_VOTING_REASON_PPB |
+ AMEC_VOTING_REASON_PMAX |
+ AMEC_VOTING_REASON_CONN_OC)))
+ {
+ l_core_freq = l_part->soft_fmin;
+ l_core_reason = AMEC_VOTING_REASON_SOFT_MIN;
+ }
+ }
+ else if(l_core_freq > l_part->soft_fmax)
+ {
+ l_core_freq = l_part->soft_fmax;
+ l_core_reason = AMEC_VOTING_REASON_SOFT_MAX;
+ }
+ }
+ }
+
+ if(CURRENT_MODE() == OCC_MODE_NOMINAL)
+ {
+ // PROC_PCAP_NOM_VOTE
+ if(g_amec->proc[0].pwr_votes.proc_pcap_nom_vote < l_core_freq)
+ {
+ l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_nom_vote;
+ l_core_reason = AMEC_VOTING_REASON_PWR;
+ l_kvm_throt_reason = POWERCAP;
+ }
+ }
+ else
+ {
+ // PROC_PCAP_VOTE
+ if(g_amec->proc[0].pwr_votes.proc_pcap_vote < l_core_freq)
+ {
+ l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_vote;
+ l_core_reason = AMEC_VOTING_REASON_PWR;
+ l_kvm_throt_reason = POWERCAP;
+ }
+ }
+
+ // Check IPS frequency request sent by Master OCC
+ if(g_amec->slv_ips_freq_request != 0)
+ {
+ if(g_amec->slv_ips_freq_request < l_core_freq)
+ {
+ l_core_freq = g_amec->slv_ips_freq_request;
+ l_core_reason = AMEC_VOTING_REASON_IPS;
+ }
+ }
+
+ // Override frequency with request from Master OCC
+ if(g_amec->foverride_enable)
+ {
+ if(g_amec->foverride != 0)
+ {
+ // Override the frequency on all cores if Master OCC sends
+ // a non-zero request
+ l_core_freq = g_amec->foverride;
+ l_core_reason = AMEC_VOTING_REASON_OVERRIDE;
+ }
+ }
+
+ if(g_amec->pstate_foverride_enable)
+ {
+ if(g_amec->pstate_foverride != 0)
+ {
+ // Override the frequency on all cores if the Global Pstate
+ // table has been modified
+ l_core_freq = g_amec->pstate_foverride;
+ l_core_reason = AMEC_VOTING_REASON_OVERRIDE;
+ }
+ }
+
+ //Make sure the frequency is not less then the system min
+ if(l_core_freq < g_amec->sys.fmin)
+ {
+ l_core_freq = g_amec->sys.fmin;
+ }
+
+ // Override frequency via Amester parameter interface
+ if (g_amec->proc[0].parm_f_override_enable &&
+ g_amec->proc[0].parm_f_override[k] > 0)
+ {
+ l_core_freq = g_amec->proc[0].parm_f_override[k];
+ l_core_reason = AMEC_VOTING_REASON_OVERRIDE_CORE;
+ }
+
+ // If frequency has changed, set the flag
+ if ( (l_core_freq != g_amec->proc[0].core[k].f_request) ||
+ (l_core_freq != g_amec->sys.fmax))
+ {
+ l_freq_req_changed = TRUE;
+ }
+
+ //STORE core frequency and reason
+ g_amec->proc[0].core[k].f_request = l_core_freq;
+ g_amec->proc[0].core[k].f_reason = l_core_reason;
+
+ // Update the Amester parameter telling us the reason. Needed for
+ // parameter array.
+ g_amec->proc[0].parm_f_reason[k] = l_core_reason;
+
+ //CURRENT_MODE() may be OCC_MODE_NOCHANGE because STATE change is processed
+ //before MODE change
+ if ((CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE) &&
+ (CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE_FP) &&
+ (CURRENT_MODE() != OCC_MODE_NOCHANGE) &&
+ (l_core_reason & NON_DPS_POWER_LIMITED))
+ {
+ G_non_dps_power_limited = TRUE;
+ }
+ else
+ {
+ G_non_dps_power_limited = FALSE;
+ }
+
+ // Update the sensor telling us what the requested frequency is
+ sensor_update( AMECSENSOR_ARRAY_PTR(FREQ250USP0C0,k),
+ (uint16_t) g_amec->proc[0].core[k].f_request);
+
+#if 0
+ /// TODO: This can be deleted if deemed useless
+ /// This trace that can be used to debug the voting
+ /// box an control loops. It will trace the reason why a
+ /// controller is lowering the freq, but will only do it once in a
+ /// row for the specific freq it wants to control to. It assumes
+ /// that all cores will be controlled to same freq.
+ if(l_chip_fmax != g_amec->sys.fmax){
+ static uint16_t L_trace = 0;
+ if(l_chip_fmax != L_trace){
+ L_trace = l_chip_fmax;
+ TRAC_INFO("Core: %d, Freq: %d, Reason: %d",k,l_core_freq,l_core_reason);
+ }
+ }
+#endif
+
+ if(l_core_freq > g_amec->proc[0].core_max_freq)
+ {
+ g_amec->proc[0].core_max_freq = l_core_freq;
+ }
+ }
+ else
+ {
+ l_core_freq = 0;
+ l_core_reason = 0;
+ }
+ }//End of for loop
+
+ // Check if the frequency is going to be changing
+ if( l_freq_req_changed == TRUE )
+ {
+ G_time_until_freq_check = FREQ_CHG_CHECK_TIME;
+ }
+ else if (G_time_until_freq_check != 0)
+ {
+ G_time_until_freq_check--;
+ }
+
+ //convert POWERCAP reason to POWER_SUPPLY_FAILURE if ovs/failsafe is asserted
+ if((l_kvm_throt_reason == POWERCAP) &&
+ (AMEC_INTF_GET_FAILSAFE() || AMEC_INTF_GET_OVERSUBSCRIPTION()))
+ {
+ l_kvm_throt_reason = POWER_SUPPLY_FAILURE;
+ }
+
+ //check if we need to update the throttle reason in homer
+ if(G_sysConfigData.system_type.kvm &&
+ (l_kvm_throt_reason != G_amec_kvm_throt_reason))
+ {
+ //Notify dcom thread to update the table
+ G_amec_kvm_throt_reason = l_kvm_throt_reason;
+ ssx_semaphore_post(&G_dcomThreadWakeupSem);
+ }
+}
+
+// Function Specification
+//
+// Name: amec_slv_freq_smh
+//
+// Description: Slave OCC's frequency state machine.
+// This function will run every tick.
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_slv_freq_smh(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t k = 0;
+ int8_t l_pstate = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ for (k=0; k<MAX_NUM_CORES; k++)
+ {
+ switch (g_amec->proc[0].core[k].f_sms)
+ {
+ case AMEC_CORE_FREQ_IDLE_STATE:
+ // Translate frequency request into a Pstate
+ l_pstate = proc_freq2pstate(g_amec->proc[0].core[k].f_request);
+
+ // Fall through
+ case AMEC_CORE_FREQ_PROCESS_STATE:
+ if(G_sysConfigData.system_type.kvm)
+ {
+ // update core bounds on kvm systems
+ proc_set_core_bounds(gpst_pmin(&G_global_pstate_table) + 1, (Pstate) l_pstate, k);
+ }
+ else
+ {
+ // update core pstate request on non-kvm systems
+ proc_set_core_pstate((Pstate) l_pstate, k);
+ }
+ break;
+ }
+ }
+}
+
+// Function Specification
+//
+// Name: amec_slv_freq_smh
+//
+// Description: Slave OCC's voting box that decides the memory speed request.
+// This function will run every tick.
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_slv_mem_voting_box(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ UINT16 l_vote;
+ UINT8 l_reason;
+ static INT16 l_slew_step = AMEC_MEMORY_STEP_SIZE;
+ static bool L_throttle_traced = FALSE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Start with max allowed speed
+ l_vote = AMEC_MEMORY_MAX_STEP;
+ l_reason = AMEC_MEM_VOTING_REASON_INIT;
+
+ // Check vote from Centaur thermal control loop
+ if (l_vote > g_amec->thermalcent.speed_request)
+ {
+ l_vote = g_amec->thermalcent.speed_request;
+ l_reason = AMEC_MEM_VOTING_REASON_CENT;
+ }
+
+ // Check vote from DIMM thermal control loop
+ if (l_vote > g_amec->thermaldimm.speed_request)
+ {
+ l_vote = g_amec->thermaldimm.speed_request;
+ l_reason = AMEC_MEM_VOTING_REASON_DIMM;
+ }
+
+ // Check if memory autoslewing is enabled
+ if (g_amec->mnfg_parms.mem_autoslew)
+ {
+ //check if we've reached the max setting and need to start going down
+ if(g_amec->mem_speed_request >= AMEC_MEMORY_MAX_STEP)
+ {
+ g_amec->mnfg_parms.mem_slew_counter++;
+ l_slew_step = -AMEC_MEMORY_STEP_SIZE;
+ }
+
+ //check if we've reached the min setting and need to start going up
+ else if(g_amec->mem_speed_request <= AMEC_MEMORY_MIN_STEP)
+ {
+ g_amec->mnfg_parms.mem_slew_counter++;
+ l_slew_step = AMEC_MEMORY_STEP_SIZE;
+ }
+
+ l_vote = g_amec->mem_speed_request + l_slew_step;
+ l_reason = AMEC_MEM_VOTING_REASON_SLEW;
+ }
+
+ // Store final vote and vote reason in g_amec
+ g_amec->mem_throttle_reason = l_reason;
+ g_amec->mem_speed_request = l_vote;
+
+ //trace changes in memory throttling
+ if(l_reason != AMEC_MEM_VOTING_REASON_INIT)
+ {
+ if(!L_throttle_traced)
+ {
+ L_throttle_traced = TRUE;
+ TRAC_INFO("Memory is being throttled. reason[%d] vote[%d] cent_expired[0x%02x] dimm_expired[0x%02x]",
+ l_reason,
+ l_vote,
+ G_cent_temp_expired_bitmap,
+ G_dimm_temp_expired_bitmap);
+ }
+ }
+ else
+ {
+ if(L_throttle_traced)
+ {
+ L_throttle_traced = FALSE;
+ TRAC_INFO("Memory is no longer being throttled");
+ }
+ }
+ return;
+}
+
+// Function Specification
+//
+// Name: amec_slv_check_perf
+//
+// Description: Slave OCC's Detect and log degraded performance errors
+// This function will run every tick.
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_slv_check_perf(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ static BOOLEAN l_prev_failsafe_state = FALSE;
+ static BOOLEAN l_prev_ovs_state = FALSE;
+ static BOOLEAN l_prev_pcap_state = FALSE;
+ static ERRL_SEVERITY l_pcap_sev = ERRL_SEV_PREDICTIVE;
+ static BOOLEAN l_throttle_traced = FALSE;
+ static uint64_t l_time = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Verify that cores are at proper frequency
+ amec_verify_pstate();
+
+ do
+ {
+ // was frequency limited by power ?
+ if ( G_non_dps_power_limited != TRUE )
+ {
+ if(l_throttle_traced)
+ {
+ TRAC_INFO("Frequency not limited by power algorithms anymore");
+ l_throttle_traced = FALSE;
+ }
+ // we are done break and return
+ break;
+ }
+
+ // frequency limited due to failsafe condition ?
+ if ( AMEC_INTF_GET_FAILSAFE() == TRUE )
+ {
+ if ( l_prev_failsafe_state == TRUE)
+ {
+ // we are done break and return
+ break;
+ }
+ else
+ {
+ // log this error ONLY ONCE per IPL
+ l_prev_failsafe_state = TRUE;
+
+ TRAC_ERR("Frequency limited due to failsafe condition(mode:%d, state:%d)",
+ CURRENT_MODE(), CURRENT_STATE());
+ l_throttle_traced = TRUE;
+ l_time = ssx_timebase_get();
+
+ // log error that calls out OVS procedure
+ // set error severity to RRL_SEV_PREDICTIVE
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_SLAVE_CHECK_PERFORMANCE
+ * @reasoncode INTERNAL_FAILURE
+ * @userdata1 Previous FailSafe State
+ * @userdata4 ERC_AMEC_SLAVE_FAILSAFE_STATE
+ * @devdesc Frequency limited due to failsafe condition
+ */
+ errlHndl_t l_errl = createErrl(AMEC_SLAVE_CHECK_PERFORMANCE, //modId
+ INTERNAL_FAILURE, //reasoncode
+ ERC_AMEC_SLAVE_FAILSAFE_STATE,//Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_prev_failsafe_state, //userdata1
+ 0); //userdata2
+
+ addCalloutToErrl( l_errl,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_OVERSUBSCRIPTION,
+ ERRL_CALLOUT_PRIORITY_HIGH
+ );
+
+ // and sets the consolidate action flag
+ setErrlActions( l_errl, ERRL_ACTIONS_CONSOLIDATE_ERRORS );
+
+ // Commit Error
+ commitErrl(&l_errl);
+
+ // we are done lets break
+ break;
+ }
+ }
+
+ // frequency limited due to oversubscription condition ?
+ if ( AMEC_INTF_GET_OVERSUBSCRIPTION() == TRUE )
+ {
+ if ( l_prev_ovs_state == TRUE)
+ {
+ // we are done break and return
+ break;
+ }
+ else
+ {
+ // log this error ONLY ONCE per IPL
+ l_prev_ovs_state = TRUE;
+
+ TRAC_ERR("Frequency limited due to oversubscription condition(mode:%d, state:%d)",
+ CURRENT_MODE(), CURRENT_STATE());
+ l_throttle_traced = TRUE;
+ l_time = ssx_timebase_get();
+
+ // log error that calls out OVS procedure
+ // set error severity to RRL_SEV_PREDICTIVE
+
+ // Updated the RC to match the actual RC passed to createErrl()
+ /* @
+ * @errortype
+ * @moduleid AMEC_SLAVE_CHECK_PERFORMANCE
+ * @reasoncode OVERSUB_LIMIT_ALERT
+ * @userdata1 Previous OVS State
+ * @userdata4 ERC_AMEC_SLAVE_OVS_STATE
+ * @devdesc Frequency limited due to oversubscription condition
+ */
+ errlHndl_t l_errl = createErrl(AMEC_SLAVE_CHECK_PERFORMANCE, //modId
+ OVERSUB_LIMIT_ALERT, //reasoncode
+ ERC_AMEC_SLAVE_OVS_STATE, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_prev_ovs_state, //userdata1
+ 0); //userdata2
+
+ // Callout to Oversubscription
+ addCalloutToErrl( l_errl,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_OVERSUBSCRIPTION,
+ ERRL_CALLOUT_PRIORITY_HIGH
+ );
+
+ // Callout to APSS
+ addCalloutToErrl( l_errl,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.apss_huid,
+ ERRL_CALLOUT_PRIORITY_MED
+ );
+
+ // Callout to Firmware
+ addCalloutToErrl( l_errl,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_LOW
+ );
+
+ // and sets the consolidate action flag
+ setErrlActions( l_errl, ERRL_ACTIONS_CONSOLIDATE_ERRORS );
+
+ // Commit Error
+ commitErrl(&l_errl);
+
+ // we are done lets break
+ break;
+ }
+ }
+
+ uint16_t l_snrBulkPwr = AMECSENSOR_PTR(PWR250US)->sample;
+
+ // frequency limited due to system power cap condition ?
+ if (( l_snrBulkPwr > (G_sysConfigData.pcap.system_pcap - PDROP_THRESH) )
+ &&
+ ( G_sysConfigData.pcap.current_pcap == 0 ))
+ {
+ if ( l_prev_pcap_state == TRUE)
+ {
+ // we are done break and return
+ break;
+ }
+ else
+ {
+ //log this error ONLY ONCE per IPL
+ l_prev_pcap_state = TRUE;
+
+ TRAC_ERR("Frequency limited due to power cap condition(mode:%d, state:%d)",
+ CURRENT_MODE(), CURRENT_STATE());
+
+ TRAC_ERR("SnrBulkPwr %d > Sys Pcap %d ",l_snrBulkPwr,
+ G_sysConfigData.pcap.system_pcap );
+
+ TRAC_ERR("SnrFanPwr %d, SnrIOPwr %d, SnrStoragePwr %d, SnrGpuPrw %d ",
+ AMECSENSOR_PTR(PWR250USFAN)->sample,
+ AMECSENSOR_PTR(PWR250USIO)->sample,
+ AMECSENSOR_PTR(PWR250USSTORE)->sample,
+ AMECSENSOR_PTR(PWR250USGPU)->sample );
+
+ TRAC_ERR("SnrProcPwr 0 %d, SnrProcPwr 1 %d, SnrProcPwr 2 %d, SnrProcPwr 3 %d",
+ g_amec->proc_snr_pwr[0],
+ g_amec->proc_snr_pwr[1],
+ g_amec->proc_snr_pwr[2],
+ g_amec->proc_snr_pwr[3] );
+
+ TRAC_ERR("SnrMemPwr 0 %d, SnrMemPwr 1 %d, SnrMemPwr 2 %d, SnrMemPwr 3 %d",
+ g_amec->mem_snr_pwr[0],
+ g_amec->mem_snr_pwr[1],
+ g_amec->mem_snr_pwr[2],
+ g_amec->mem_snr_pwr[3] );
+
+
+ l_throttle_traced = TRUE;
+ l_time = ssx_timebase_get();
+
+ // log error that calls out firmware and APSS procedure
+ // set error severity to l_pcap_sev
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_SLAVE_CHECK_PERFORMANCE
+ * @reasoncode PCAP_THROTTLE_POWER_LIMIT
+ * @userdata1 Current Sensor Bulk Power
+ * @userdata2 System PCAP
+ * @userdata4 ERC_AMEC_SLAVE_POWERCAP
+ * @devdesc Frequency limited due to PowerCap condition
+ */
+ errlHndl_t l_errl = createErrl(AMEC_SLAVE_CHECK_PERFORMANCE, //modId
+ PCAP_THROTTLE_POWER_LIMIT, //reasoncode
+ ERC_AMEC_SLAVE_POWERCAP, //Extended reason code
+ l_pcap_sev, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_snrBulkPwr, //userdata1
+ G_sysConfigData.pcap.system_pcap);//userdata2
+
+ addCalloutToErrl( l_errl,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH
+ );
+
+ addCalloutToErrl( l_errl,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.apss_huid,
+ ERRL_CALLOUT_PRIORITY_HIGH
+ );
+
+ // and sets the consolidate action flag
+ setErrlActions( l_errl, ERRL_ACTIONS_CONSOLIDATE_ERRORS );
+
+ // then l_pcap_sev to informational
+ l_pcap_sev = ERRL_SEV_INFORMATIONAL;
+
+ // Commit Error
+ commitErrl(&l_errl);
+
+ // we are done lets break
+ break;
+ }
+ }
+
+ // trottle trace to every 3600 seconds (1hr = 3600000)
+ if(!l_throttle_traced && ( DURATION_IN_MS_UNTIL_NOW_FROM(l_time) > 3600000 ) )
+ {
+ TRAC_INFO("Frequency power limited due to transient condition: PowerLimited=%x, FailSafe=%x, OverSubScription=%x CurrentBulkPwr=%x",
+ G_non_dps_power_limited, AMEC_INTF_GET_FAILSAFE(), AMEC_INTF_GET_OVERSUBSCRIPTION(), l_snrBulkPwr );
+ l_throttle_traced = TRUE;
+
+ l_time = ssx_timebase_get();
+ }
+ }
+ while( 0 );
+
+ return;
+}
+
+// Verifies that each core is at the correct frequency after they have had
+// time to stabilize
+void amec_verify_pstate()
+{
+ uint8_t l_core = 0;
+ int8_t l_pstate_from_fmax = 0;
+ gpe_bulk_core_data_t * l_core_data_ptr;
+ pmc_pmsr_ffcdc_data_t l_pmc_pmsr_ffdc;
+ errlHndl_t l_err = NULL;
+
+ if ( (G_time_until_freq_check == 0) &&
+ ( CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE ) &&
+ ( CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE_FP ) &&
+ (!G_sysConfigData.system_type.kvm))
+ {
+ // Reset the counter
+ G_time_until_freq_check = FREQ_CHG_CHECK_TIME;
+
+ // Convert fmax to the corresponding pstate
+ l_pstate_from_fmax = proc_freq2pstate(g_amec->sys.fmax);
+
+ for( l_core = 0; l_core < MAX_NUM_CORES; l_core++ )
+ {
+ // If the core isn't present, skip it
+ if(!CORE_PRESENT(l_core))
+ {
+ l_pmc_pmsr_ffdc.pmsr_ffdc_data.data[l_core].value = 0;
+ continue;
+ }
+
+ // Get pointer to core data
+ l_core_data_ptr = proc_get_bulk_core_data_ptr(l_core);
+
+ // Get the core's pmsr data
+ l_pmc_pmsr_ffdc.pmsr_ffdc_data.data[l_core] = l_core_data_ptr->pcb_slave.pmsr;
+
+ // Verify that the core is running at the correct frequency
+ // If not, log an error
+ if( (l_pstate_from_fmax != l_pmc_pmsr_ffdc.pmsr_ffdc_data.data[l_core].fields.local_pstate_actual) &&
+ (l_pstate_from_fmax > l_pmc_pmsr_ffdc.pmsr_ffdc_data.data[l_core].fields.pv_min) &&
+ (l_err == NULL) )
+ {
+ TRAC_ERR("Frequency mismatch in core %d: actual_ps[%d] req_ps[%d] fmax[%d] mode[%d].",
+ l_core,
+ l_pmc_pmsr_ffdc.pmsr_ffdc_data.data[l_core].fields.local_pstate_actual,
+ l_pstate_from_fmax,
+ g_amec->sys.fmax,
+ CURRENT_MODE());
+
+ fill_pmc_ffdc_buffer(&l_pmc_pmsr_ffdc.pmc_ffcdc_data);
+
+ /* @
+ * @moduleid AMEC_VERIFY_FREQ_MID
+ * @reasonCode TARGET_FREQ_FAILURE
+ * @severity ERRL_SEV_PREDICTIVE
+ * @userdata1 0
+ * @userdata2 0
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc A core is not running at the expected frequency
+ */
+ l_err = createErrl( AMEC_VERIFY_FREQ_MID, // i_modId,
+ TARGET_FREQ_FAILURE, // i_reasonCode,
+ OCC_NO_EXTENDED_RC,
+ ERRL_SEV_UNRECOVERABLE,
+ NULL, // i_trace,
+ DEFAULT_TRACE_SIZE, // i_traceSz,
+ 0, // i_userData1,
+ 0); // i_userData2
+
+ //Add firmware callout
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ //Add processor callout
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.proc_huid,
+ ERRL_CALLOUT_PRIORITY_MED);
+ }
+ }
+
+ if( l_err != NULL)
+ {
+ //Add our register dump to the error log
+ addUsrDtlsToErrl(l_err,
+ (uint8_t*) &l_pmc_pmsr_ffdc,
+ sizeof(l_pmc_pmsr_ffdc),
+ ERRL_USR_DTL_STRUCT_VERSION_1,
+ ERRL_USR_DTL_BINARY_DATA);
+
+ REQUEST_RESET(l_err);
+ }
+ }
+}
+
+// Fills in a pmc ffdc buffer with lots of PMC related OCI and SCOM registers
+void fill_pmc_ffdc_buffer(pmc_ffdc_data_t* i_ffdc_ptr)
+{
+ int i;
+ uint32_t l_rc, l_addr, l_data32;
+ uint64_t l_data64;
+
+ //clear out the entire buffer
+ memset(i_ffdc_ptr, 0, sizeof(pmc_ffdc_data_t));
+
+ //first get the OCI accessible FFDC data
+ for(i = 0; i < PMC_FFDC_OCI_ADDRS_SIZE; i++)
+ {
+ l_addr = G_pmc_ffdc_oci_addrs[i];
+ if(l_addr)
+ {
+ l_data32 = in32(l_addr);
+ }
+ else
+ {
+ //leave an entry with all zero address and data for eye catcher
+ break;
+ }
+
+ //store address along with data for easier parsing
+ i_ffdc_ptr->oci_regs[i].addr = l_addr;
+ i_ffdc_ptr->oci_regs[i].data = l_data32;
+ }
+
+ //then get the SCOM accessible FFDC data
+ for(i = 0; i < PMC_FFDC_SCOM_ADDRS_SIZE; i++)
+ {
+ l_addr = G_pmc_ffdc_scom_addrs[i];
+ l_rc = (uint32_t)_getscom(l_addr, &l_data64, SCOM_TIMEOUT);
+ if(l_rc)
+ {
+ //indicate there was a scom failure in collecting the data
+ l_data64 = 0xFEEDB0B000000000ull;
+
+ //store rc in lower word
+ l_data64 |= l_rc;
+ }
+
+ //store address along with data for easier parsing
+ i_ffdc_ptr->scom_regs[i].addr = l_addr;
+ i_ffdc_ptr->scom_regs[i].data = l_data64;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_freq.h b/src/occ_405/amec/amec_freq.h
new file mode 100644
index 0000000..b05277d
--- /dev/null
+++ b/src/occ_405/amec/amec_freq.h
@@ -0,0 +1,170 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_freq.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 _AMEC_FREQ_H
+#define _AMEC_FREQ_H
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include "occ_sys_config.h"
+#include <ssx_app_cfg.h>
+#include <amec_smh.h>
+#include <mode.h>
+#include <errl.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+#define FREQ_CHG_CHECK_TIME 4000
+
+// This is used by the Frequency State Machine
+typedef enum
+{
+ AMEC_CORE_FREQ_IDLE_STATE = 0x00,
+ AMEC_CORE_FREQ_PROCESS_STATE = 0x01,
+}amec_freq_write_state_t;
+
+// This is reason code used by Voting box amec_slv_voting_box
+typedef enum
+{
+ AMEC_VOTING_REASON_INIT = 0x00000000,
+ AMEC_VOTING_REASON_PHYP = 0x00000001,
+ AMEC_VOTING_REASON_PLPM = 0x00000002,
+ AMEC_VOTING_REASON_LEGACY = 0x00000004,
+ AMEC_VOTING_REASON_SOFT_MIN = 0x00000008,
+ AMEC_VOTING_REASON_SOFT_MAX = 0x00000010,
+ AMEC_VOTING_REASON_CORE_CAP = 0x00000020,
+ AMEC_VOTING_REASON_PROC_THRM = 0x00000040,
+ AMEC_VOTING_REASON_GXHB_THRM = 0x00000080,
+ AMEC_VOTING_REASON_VRHOT_THRM = 0x00000100,
+ AMEC_VOTING_REASON_OVER_CURRENT = 0x00000200,
+ AMEC_VOTING_REASON_OVERRIDE = 0x00000400,
+ AMEC_VOTING_REASON_CORE_GRP_MIN = 0x00000800,
+ AMEC_VOTING_REASON_PWR = 0x00001000,
+ AMEC_VOTING_REASON_PPB = 0x00002000,
+ AMEC_VOTING_REASON_PMAX = 0x00004000,
+ AMEC_VOTING_REASON_UTIL = 0x00008000,
+ AMEC_VOTING_REASON_CONN_OC = 0x00010000,
+ AMEC_VOTING_REASON_OVERRIDE_CORE = 0x00020000,
+ AMEC_VOTING_REASON_IPS = 0x00040000,
+ AMEC_VOTING_REASON_APSS_PMAX = 0x00080000,
+}amec_freq_voting_reason_t;
+
+
+#define NON_DPS_POWER_LIMITED ( AMEC_VOTING_REASON_PWR | \
+ AMEC_VOTING_REASON_PPB | \
+ AMEC_VOTING_REASON_PMAX \
+ )
+
+extern BOOLEAN G_non_dps_power_limited;
+
+// This is reason code used by Voting box amec_slv_mem_voting_box
+typedef enum
+{
+ AMEC_MEM_VOTING_REASON_INIT = 0,
+ AMEC_MEM_VOTING_REASON_CENT = 1,
+ AMEC_MEM_VOTING_REASON_DIMM = 2,
+ AMEC_MEM_VOTING_REASON_SLEW = 3,
+}amec_mem_voting_reason_t;
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+#define PMC_FFDC_OCI_ADDRS_SIZE 34
+#define PMC_FFDC_SCOM_ADDRS_SIZE 5
+
+// scom ffdc format
+typedef struct __attribute__ ((packed))
+{
+ uint32_t addr;
+ uint64_t data;
+} pmc_ffdc_scom_entry_t;
+
+// OCI ffdc format
+typedef struct
+{
+ uint32_t addr;
+ uint32_t data;
+} pmc_ffdc_oci_entry_t;
+
+//PMC FFDC format for user detail section of error log
+typedef struct
+{
+ pmc_ffdc_oci_entry_t oci_regs[PMC_FFDC_OCI_ADDRS_SIZE];
+ pmc_ffdc_scom_entry_t scom_regs[PMC_FFDC_SCOM_ADDRS_SIZE];
+} pmc_ffdc_data_t;
+
+typedef struct
+{
+ pcbs_power_management_status_reg_t data[MAX_NUM_CORES];
+} pmsr_ffdc_data_t;
+
+typedef struct
+{
+ pmc_ffdc_data_t pmc_ffcdc_data;
+ pmsr_ffdc_data_t pmsr_ffdc_data;
+} pmc_pmsr_ffcdc_data_t;
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+void fill_pmc_ffdc_buffer(pmc_ffdc_data_t* i_ffdc_ptr);
+
+// Used to set the freq range that amec can control between.
+errlHndl_t amec_set_freq_range(const OCC_MODE i_mode);
+
+// Voting box for handling slave freq votes
+void amec_slv_voting_box(void);
+
+// Amec Frequency State Machine
+void amec_slv_freq_smh(void);
+
+// Voting box for handling slave memory freq votes
+void amec_slv_mem_voting_box(void);
+
+// Amec Detect and log degraded performance errors
+void amec_slv_check_perf(void);
+
+// Verifies that each core is at the correct frequency
+void amec_verify_pstate();
+
+#endif
+
diff --git a/src/occ_405/amec/amec_health.c b/src/occ_405/amec/amec_health.c
new file mode 100755
index 0000000..4efad15
--- /dev/null
+++ b/src/occ_405/amec/amec_health.c
@@ -0,0 +1,1034 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_health.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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include "amec_health.h"
+#include "amec_sys.h"
+#include "amec_service_codes.h"
+#include "occ_service_codes.h"
+#include <centaur_data.h>
+#include <thrm_thread.h>
+#include <proc_data.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+extern thrm_fru_data_t G_thrm_fru_data[DATA_FRU_MAX];
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+// Have we already called out the dimm for overtemp (bitmap of dimms)?
+cent_sensor_flags_t G_dimm_overtemp_logged_bitmap = {0};
+
+// Have we already called out the dimm for timeout (bitmap of dimms)?
+cent_sensor_flags_t G_dimm_timeout_logged_bitmap = {0};
+
+// Are any dimms currently in the timedout state (bitmap of centaurs)?
+// Note: this only tells you which centaur, not which dimm.
+uint8_t G_dimm_temp_expired_bitmap = 0;
+
+// Have we already called out the centaur for timeout (bitmap of centaurs)?
+uint8_t G_cent_timeout_logged_bitmap = 0;
+
+// Have we already called out the centaur for overtemp (bitmap of centaurs)?
+uint8_t G_cent_overtemp_logged_bitmap = 0;
+
+// Are any dimms currently in the timedout state (bitmap of centaurs)?
+uint8_t G_cent_temp_expired_bitmap = 0;
+
+// Array to store the update tag of each core's temperature sensor
+uint32_t G_core_temp_update_tag[MAX_NUM_CORES] = {0};
+
+//*************************************************************************
+// Function Declarations
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+uint64_t amec_mem_get_huid(uint8_t i_cent, uint8_t i_dimm)
+{
+ uint64_t l_huid;
+
+ if(i_dimm == 0xff)
+ {
+ //we're being asked for a centaur huid
+ l_huid = G_sysConfigData.centaur_huids[i_cent];
+ }
+ else
+ {
+ //we're being asked for a dimm huid
+ l_huid = G_sysConfigData.dimm_huids[i_cent][i_dimm];
+ if(!l_huid)
+ {
+ //if we don't have a valid dimm huid, use the
+ //centaur huid.
+ //TODO: this will not work for ISDIMMS.
+ l_huid = G_sysConfigData.centaur_huids[i_cent];
+ }
+ }
+ return l_huid;
+}
+
+//If i_dimm is 0xff it is assumed that the caller wishes to
+//mark the centaur as being logged. Otherwise, it is assumed
+//that the dimm should be marked.
+void amec_mem_mark_logged(uint8_t i_cent,
+ uint8_t i_dimm,
+ uint8_t* i_clog_bitmap,
+ uint8_t* i_dlog_bitmap)
+{
+ if(i_dimm == 0xff)
+ {
+ //mark the centaur as being called out.
+ *i_clog_bitmap |= CENTAUR0_PRESENT_MASK >> i_cent;
+ }
+ else
+ {
+ //mark the dimm as being called out.
+ *i_dlog_bitmap |= DIMM_SENSOR0 >> i_dimm;
+ }
+}
+
+void amec_health_check_dimm_temp()
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_ot_error, l_cur_temp, l_max_temp;
+ sensor_t *l_sensor;
+ uint32_t l_cent, l_dimm;
+ uint32_t l_callouts_count = 0;
+ uint8_t l_new_callouts;
+ uint64_t l_huid;
+ errlHndl_t l_err = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Check to see if any dimms have reached the error temperature that
+ // haven't been called out already
+ if(G_dimm_overtemp_bitmap.bigword == G_dimm_overtemp_logged_bitmap.bigword)
+ {
+ return;
+ }
+
+ l_ot_error = g_amec->thermaldimm.ot_error;
+ l_sensor = getSensorByGsid(TEMP2MSDIMM);
+ l_cur_temp = l_sensor->sample;
+ l_max_temp = l_sensor->sample_max;
+ TRAC_ERR("amec_health_check_dimm_temp: DIMM reached error temp[%d]. cur_max[%d], hist_max[%d]",
+ l_ot_error,
+ l_cur_temp,
+ l_max_temp);
+
+ //iterate over all centaurs
+ for(l_cent = 0; l_cent < MAX_NUM_CENTAURS; l_cent++)
+ {
+ //only callout a dimm if it hasn't been called out already
+ l_new_callouts = G_dimm_overtemp_bitmap.bytes[l_cent] ^
+ G_dimm_overtemp_logged_bitmap.bytes[l_cent];
+
+ //skip to next centaur if no new callouts for this one
+ if(!l_new_callouts)
+ {
+ continue;
+ }
+
+ //find the dimm(s) that need to be called out behind this centaur
+ for(l_dimm = 0; l_dimm < NUM_DIMMS_PER_CENTAUR; l_dimm++)
+ {
+ if(!(l_new_callouts & (DIMM_SENSOR0 >> l_dimm)))
+ {
+ continue;
+ }
+
+ l_huid = amec_mem_get_huid(l_cent, l_dimm);
+
+ amec_mem_mark_logged(l_cent,
+ l_dimm,
+ &G_cent_overtemp_logged_bitmap,
+ &G_dimm_overtemp_logged_bitmap.bytes[l_cent]);
+
+ //If we don't have an error log for the callout, create one
+ if(!l_err)
+ {
+ /* @
+ * @errortype
+ * @moduleid AMEC_HEALTH_CHECK_DIMM_TEMP
+ * @reasoncode DIMM_ERROR_TEMP
+ * @userdata1 Maximum dimm temperature
+ * @userdata2 Dimm temperature threshold
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Memory DIMM(s) exceeded maximum safe
+ * temperature.
+ */
+ l_err = createErrl(AMEC_HEALTH_CHECK_DIMM_TEMP, //modId
+ DIMM_ERROR_TEMP, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_max_temp, //userdata1
+ l_ot_error); //userdata2
+
+ // Callout the "over temperature" procedure
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_OVER_TEMPERATURE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+ l_callouts_count = 1;
+ }
+
+ // Callout dimm
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ l_huid,
+ ERRL_CALLOUT_PRIORITY_MED);
+
+ l_callouts_count++;
+
+ //If we've reached the max # of callouts for an error log
+ //commit the error log
+ if(l_callouts_count == ERRL_MAX_CALLOUTS)
+ {
+ commitErrl(&l_err);
+ }
+
+ //If we found all of the callouts for this centaur, go to the next one
+ if(!l_new_callouts)
+ {
+ break;
+ }
+ }//iterate over dimms
+ }//iterate over centaurs
+
+ if(l_err)
+ {
+ commitErrl(&l_err);
+ }
+}
+
+void amec_health_check_cent_temp()
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_ot_error, l_cur_temp, l_max_temp;
+ sensor_t *l_sensor;
+ uint32_t l_cent;
+ uint32_t l_callouts_count = 0;
+ uint8_t l_new_callouts;
+ uint64_t l_huid;
+ errlHndl_t l_err = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Check to see if any centaurs have reached the error temperature that
+ // haven't been called out already
+ l_new_callouts = G_cent_overtemp_bitmap ^ G_cent_overtemp_logged_bitmap;
+ if(!l_new_callouts)
+ {
+ return;
+ }
+
+ l_ot_error = g_amec->thermalcent.ot_error;
+ l_sensor = getSensorByGsid(TEMP2MSCENT);
+ l_cur_temp = l_sensor->sample;
+ l_max_temp = l_sensor->sample_max;
+ TRAC_ERR("amec_health_check_cent_temp: Centaur reached error temp[%d]. cur_max[%d], hist_max[%d] bitmap[0x%02X]",
+ l_ot_error,
+ l_cur_temp,
+ l_max_temp,
+ l_new_callouts);
+
+ //find the centaur(s) that need to be called out
+ for(l_cent = 0; l_cent < MAX_NUM_CENTAURS; l_cent++)
+ {
+ if(!(l_new_callouts & (CENTAUR0_PRESENT_MASK >> l_cent)))
+ {
+ continue;
+ }
+
+ l_huid = amec_mem_get_huid(l_cent, 0xff);
+
+ amec_mem_mark_logged(l_cent,
+ 0xff,
+ &G_cent_overtemp_logged_bitmap,
+ &G_dimm_overtemp_logged_bitmap.bytes[l_cent]);
+
+ //If we don't have an error log for the callout, create one
+ if(!l_err)
+ {
+ /* @
+ * @errortype
+ * @moduleid AMEC_HEALTH_CHECK_CENT_TEMP
+ * @reasoncode CENT_ERROR_TEMP
+ * @userdata1 Maximum centaur temperature
+ * @userdata2 Centaur temperature threshold
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Centaur memory controller(s) exceeded maximum safe
+ * temperature.
+ */
+ l_err = createErrl(AMEC_HEALTH_CHECK_CENT_TEMP, //modId
+ CENT_ERROR_TEMP, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_max_temp, //userdata1
+ l_ot_error); //userdata2
+
+ // Callout the "over temperature" procedure
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_OVER_TEMPERATURE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+ l_callouts_count = 1;
+ }
+
+ // Callout centaur
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ l_huid,
+ ERRL_CALLOUT_PRIORITY_MED);
+
+ l_callouts_count++;
+
+ //If we've reached the max # of callouts for an error log
+ //commit the error log
+ if(l_callouts_count == ERRL_MAX_CALLOUTS)
+ {
+ commitErrl(&l_err);
+ }
+
+ }//iterate over centaurs
+
+ if(l_err)
+ {
+ commitErrl(&l_err);
+ }
+}
+
+void amec_health_check_dimm_timeout()
+{
+ static cent_sensor_flags_t L_temp_update_bitmap_prev = {0};
+ cent_sensor_flags_t l_need_inc, l_need_clr, l_temp_update_bitmap;
+ uint8_t l_dimm, l_cent;
+ fru_temp_t* l_fru;
+ errlHndl_t l_err = NULL;
+ uint32_t l_callouts_count = 0;
+ uint64_t l_huid;
+ static bool L_ran_once = FALSE;
+
+ do
+ {
+ //For every dimm sensor there are 3 cases to consider
+ //
+ //1) sensor is enabled and not updated (need to increment timer and check for timeout)
+ //2) sensor is enabled and updated but wasn't updated on previous check (need to clear timer)
+ //3) sensor is enabled and updated and was updated on previous check (do nothing)
+
+ //Grab snapshot of G_dimm_temp_updated_bitmap and clear it
+ l_temp_update_bitmap.bigword = G_dimm_temp_updated_bitmap.bigword;
+ G_dimm_temp_updated_bitmap.bigword = 0;
+
+ //check if we need to increment any timers (haven't been updated in the last second)
+ l_need_inc.bigword = G_cent_enabled_sensors.bigword & ~l_temp_update_bitmap.bigword;
+
+ //check if we need to clear any timers (updated now but not updated previously)
+ l_need_clr.bigword = l_temp_update_bitmap.bigword & ~L_temp_update_bitmap_prev.bigword;
+
+ //save off the previous bitmap of updated sensors for next time
+ L_temp_update_bitmap_prev.bigword = l_temp_update_bitmap.bigword;
+
+ //only go further if we actually have work to do here.
+ if(!l_need_inc.bigword && !l_need_clr.bigword)
+ {
+ //nothing to do
+ break;
+ }
+
+ //iterate across all centaurs incrementing dimm sensor timers as needed
+ for(l_cent = 0; l_cent < MAX_NUM_CENTAURS; l_cent++)
+ {
+ //any dimm timers behind this centaur need incrementing?
+ if(!l_need_inc.bytes[l_cent])
+ {
+ //all dimm sensors were updated for this centaur. Clear the dimm timeout bit for this centaur.
+ if(G_dimm_temp_expired_bitmap & (CENTAUR0_PRESENT_MASK >> l_cent))
+ {
+ G_dimm_temp_expired_bitmap &= ~(CENTAUR0_PRESENT_MASK >> l_cent);
+ TRAC_INFO("All dimm sensors for centaur %d have been updated", l_cent);
+ }
+ continue;
+ }
+
+ //There's at least one dimm requiring an increment, find the dimm
+ for(l_dimm = 0; l_dimm < NUM_DIMMS_PER_CENTAUR; l_dimm++)
+ {
+ //not this one, go to next one
+ if(!(l_need_inc.bytes[l_cent] & (DIMM_SENSOR0 >> l_dimm)))
+ {
+ continue;
+ }
+
+ //we found one.
+ l_fru = &g_amec->proc[0].memctl[l_cent].centaur.dimm_temps[l_dimm];
+
+ //increment timer
+ l_fru->sample_age++;
+
+ //handle wrapping
+ if(!l_fru->sample_age)
+ {
+ l_fru->sample_age = -1;
+ }
+
+ //info trace each transition to not having a new temperature
+ if(l_fru->sample_age == 1)
+ {
+ TRAC_INFO("Failed to read dimm temperature on cent[%d] dimm[%d] temp[%d] flags[0x%02X]",
+ l_cent, l_dimm, l_fru->cur_temp, l_fru->flags);
+ }
+
+ //check if the temperature reading is still useable
+ if(g_amec->thermaldimm.temp_timeout == 0xff ||
+ l_fru->sample_age < g_amec->thermaldimm.temp_timeout)
+ {
+ continue;
+ }
+
+ //temperature has expired. Notify control algorithms which centaur.
+ if(!(G_dimm_temp_expired_bitmap & (CENTAUR0_PRESENT_MASK >> l_cent)))
+ {
+ G_dimm_temp_expired_bitmap |= CENTAUR0_PRESENT_MASK >> l_cent;
+ TRAC_ERR("Timed out reading dimm temperature sensor on cent %d.",
+ l_cent);
+ }
+
+ //If we've already logged an error for this FRU go to the next one.
+ if(G_dimm_timeout_logged_bitmap.bytes[l_cent] & (DIMM_SENSOR0 >> l_dimm))
+ {
+ continue;
+ }
+
+ TRAC_ERR("Timed out reading dimm temperature on cent[%d] dimm[%d] temp[%d] flags[0x%02X]",
+ l_cent, l_dimm, l_fru->cur_temp, l_fru->flags);
+
+ if(!l_err)
+ {
+ /* @
+ * @errortype
+ * @moduleid AMEC_HEALTH_CHECK_DIMM_TIMEOUT
+ * @reasoncode FRU_TEMP_TIMEOUT
+ * @userdata1 timeout value in seconds
+ * @userdata2 0
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Failed to read a memory DIMM temperature
+ *
+ */
+ l_err = createErrl(AMEC_HEALTH_CHECK_DIMM_TIMEOUT, //modId
+ FRU_TEMP_TIMEOUT, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ g_amec->thermaldimm.temp_timeout, //userdata1
+ 0); //userdata2
+
+ l_callouts_count = 0;
+ }
+
+ //Get the HUID for the dimm
+ l_huid = amec_mem_get_huid(l_cent, l_dimm);
+
+ // Callout dimm
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ l_huid,
+ ERRL_CALLOUT_PRIORITY_MED);
+
+ l_callouts_count++;
+
+ //If we've reached the max # of callouts for an error log
+ //commit the error log
+ if(l_callouts_count == ERRL_MAX_CALLOUTS)
+ {
+ commitErrl(&l_err);
+ }
+
+ //Mark dimm as logged so we don't log it more than once
+ amec_mem_mark_logged(l_cent,
+ l_dimm,
+ &G_cent_timeout_logged_bitmap,
+ &G_dimm_timeout_logged_bitmap.bytes[l_cent]);
+ } //iterate over all dimms
+
+ } //iterate over all centaurs
+
+ if(l_err)
+ {
+ commitErrl(&l_err);
+ }
+
+ //skip clearing if no dimms need it
+ if(!l_need_clr.bigword)
+ {
+ break;
+ }
+
+ //iterate across all centaurs clearing dimm sensor timers as needed
+ for(l_cent = 0; l_cent < MAX_NUM_CENTAURS; l_cent++)
+ {
+
+ if(!l_need_clr.bytes[l_cent])
+ {
+ continue;
+ }
+
+ //iterate over all dimms
+ for(l_dimm = 0; l_dimm < NUM_DIMMS_PER_CENTAUR; l_dimm++)
+ {
+ //not this one, go to next one
+ if(!(l_need_clr.bytes[l_cent] & (DIMM_SENSOR0 >> l_dimm)))
+ {
+ continue;
+ }
+
+ //we found one.
+ l_fru = &g_amec->proc[0].memctl[l_cent].centaur.dimm_temps[l_dimm];
+
+ //clear timer
+ l_fru->sample_age = 0;
+
+ //info trace each time we recover
+ if(L_ran_once)
+ {
+ TRAC_INFO("DIMM temperature collection has resumed on cent[%d] dimm[%d] temp[%d]",
+ l_cent, l_dimm, l_fru->cur_temp);
+ }
+
+ }//iterate over all dimms
+ }//iterate over all centaurs
+ }while(0);
+ L_ran_once = TRUE;
+ G_thrm_fru_data[DATA_FRU_DIMM].read_failure = G_dimm_temp_expired_bitmap;
+}
+
+void amec_health_check_cent_timeout()
+{
+ static uint8_t L_temp_update_bitmap_prev = 0;
+ uint8_t l_need_inc, l_need_clr, l_temp_update_bitmap;
+ uint8_t l_cent;
+ fru_temp_t* l_fru;
+ errlHndl_t l_err = NULL;
+ uint32_t l_callouts_count = 0;
+ uint64_t l_huid;
+ static bool L_ran_once = FALSE;
+
+ do
+ {
+ //For every centaur sensor there are 3 cases to consider
+ //
+ //1) centaur is present and not updated (need to increment timer and check for timeout)
+ //2) centaur is present and updated but wasn't updated on previous check (need to clear timer)
+ //3) centaur is present and updated and was updated on previous check (do nothing)
+
+ //Grab snapshot of G_cent_temp_update_bitmap and clear it
+ l_temp_update_bitmap = G_cent_temp_updated_bitmap;
+ G_cent_temp_updated_bitmap = 0;
+
+ //check if we need to increment any timers
+ l_need_inc = G_present_centaurs & ~l_temp_update_bitmap;
+
+ //check if we need to clear any timers
+ l_need_clr = l_temp_update_bitmap & ~L_temp_update_bitmap_prev;
+
+ //only go further if we actually have work to do here.
+ if(!l_need_inc && !l_need_clr)
+ {
+ //nothing to do
+ break;
+ }
+
+ //save off the previous bitmap of updated sensors
+ L_temp_update_bitmap_prev = l_temp_update_bitmap;
+
+ //iterate across all centaurs incrementing timers as needed
+ for(l_cent = 0; l_cent < MAX_NUM_CENTAURS; l_cent++)
+ {
+ //does this centaur timer need incrementing?
+ if(!(l_need_inc & (CENTAUR0_PRESENT_MASK >> l_cent)))
+ {
+ //temperature was updated for this centaur. Clear the timeout bit for this centaur.
+ if(G_cent_temp_expired_bitmap & (CENTAUR0_PRESENT_MASK >> l_cent))
+ {
+ G_cent_temp_expired_bitmap &= ~(CENTAUR0_PRESENT_MASK >> l_cent);
+ TRAC_INFO("centaur %d temps have been updated", l_cent);
+ }
+ continue;
+ }
+
+ //This centaur requires an increment
+ l_fru = &g_amec->proc[0].memctl[l_cent].centaur.centaur_hottest;
+
+ //increment timer
+ l_fru->sample_age++;
+
+ //handle wrapping
+ if(!l_fru->sample_age)
+ {
+ l_fru->sample_age = -1;
+ }
+
+ //info trace each transition to not having a new temperature
+ if(l_fru->sample_age == 1)
+ {
+ TRAC_INFO("Failed to read centaur temperature on cent[%d] temp[%d] flags[0x%02X]",
+ l_cent, l_fru->cur_temp, l_fru->flags);
+ }
+
+ //check if the temperature reading is still useable
+ if(g_amec->thermalcent.temp_timeout == 0xff ||
+ l_fru->sample_age < g_amec->thermalcent.temp_timeout)
+ {
+ continue;
+ }
+
+ //temperature has expired. Notify control algorithms which centaur.
+ if(!(G_cent_temp_expired_bitmap & (CENTAUR0_PRESENT_MASK >> l_cent)))
+ {
+ G_cent_temp_expired_bitmap |= CENTAUR0_PRESENT_MASK >> l_cent;
+ TRAC_ERR("Timed out reading centaur temperature sensor on cent %d",
+ l_cent);
+ }
+
+ //If we've already logged an error for this FRU go to the next one.
+ if(G_cent_timeout_logged_bitmap & (CENTAUR0_PRESENT_MASK >> l_cent))
+ {
+ continue;
+ }
+
+ TRAC_ERR("Timed out reading centaur temperature on cent[%d] temp[%d] flags[0x%02X]",
+ l_cent, l_fru->cur_temp, l_fru->flags);
+
+ if(!l_err)
+ {
+ /* @
+ * @errortype
+ * @moduleid AMEC_HEALTH_CHECK_CENT_TIMEOUT
+ * @reasoncode FRU_TEMP_TIMEOUT
+ * @userdata1 timeout value in seconds
+ * @userdata2 0
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Failed to read a centaur memory controller
+ * temperature
+ *
+ */
+ l_err = createErrl(AMEC_HEALTH_CHECK_CENT_TIMEOUT, //modId
+ FRU_TEMP_TIMEOUT, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ g_amec->thermalcent.temp_timeout, //userdata1
+ 0); //userdata2
+
+ l_callouts_count = 0;
+ }
+
+ //Get the HUID for the centaur
+ l_huid = amec_mem_get_huid(l_cent, 0xff);
+
+ // Callout centaur
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ l_huid,
+ ERRL_CALLOUT_PRIORITY_MED);
+
+ l_callouts_count++;
+
+ //If we've reached the max # of callouts for an error log
+ //commit the error log
+ if(l_callouts_count == ERRL_MAX_CALLOUTS)
+ {
+ commitErrl(&l_err);
+ }
+
+ //Mark centaur as logged so we don't log it more than once
+ amec_mem_mark_logged(l_cent,
+ 0xff,
+ &G_cent_timeout_logged_bitmap,
+ &G_dimm_timeout_logged_bitmap.bytes[l_cent]);
+ } //iterate over all centaurs
+
+ if(l_err)
+ {
+ commitErrl(&l_err);
+ }
+
+ //skip clearing timers if no centaurs need it
+ if(!l_need_clr)
+ {
+ break;
+ }
+
+ //iterate across all centaurs clearing timers as needed
+ for(l_cent = 0; l_cent < MAX_NUM_CENTAURS; l_cent++)
+ {
+ //not this one, go to next one
+ if(!(l_need_clr & (CENTAUR0_PRESENT_MASK >> l_cent)))
+ {
+ continue;
+ }
+
+ //we found one.
+ l_fru = &g_amec->proc[0].memctl[l_cent].centaur.centaur_hottest;
+
+ //clear timer
+ l_fru->sample_age = 0;
+
+ //info trace each time we recover
+ if(L_ran_once)
+ {
+ TRAC_INFO("centaur temperature collection has resumed on cent[%d] temp[%d]",
+ l_cent, l_fru->cur_temp);
+ }
+
+ }//iterate over all centaurs
+ }while(0);
+ L_ran_once = TRUE;
+ G_thrm_fru_data[DATA_FRU_CENTAUR].read_failure = G_cent_temp_expired_bitmap;
+}
+
+
+// Function Specification
+//
+// Name: amec_health_check_proc_temp
+//
+// Description: This function checks if the proc temperature has
+// exceeded the error temperature as define in data format 0x13.
+//
+// End Function Specification
+void amec_health_check_proc_temp()
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_ot_error;
+ static uint32_t l_error_count = 0;
+ static BOOLEAN l_ot_error_logged = FALSE;
+ sensor_t *l_sensor;
+ errlHndl_t l_err = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ // Get TEMP2MSP0PEAK sensor, which is hottest core temperature
+ // in OCC processor
+ l_sensor = getSensorByGsid(TEMP2MSP0PEAK);
+ l_ot_error = g_amec->thermalproc.ot_error;
+
+ // Check to see if we exceeded our error temperature
+ if (l_sensor->sample > l_ot_error)
+ {
+ // Increment the error counter for this FRU
+ l_error_count++;
+
+ // Trace and log error the first time this occurs
+ if (l_error_count == AMEC_HEALTH_ERROR_TIMER)
+ {
+ // Have we logged an OT error for this FRU already?
+ if (l_ot_error_logged == TRUE)
+ {
+ break;
+ }
+
+ l_ot_error_logged = TRUE;
+
+ TRAC_ERR("amec_health_check_error_temp: processor has exceeded OT error! temp[%u] ot_error[%u]",
+ l_sensor->sample,
+ l_ot_error);
+
+ // Log an OT error
+ /* @
+ * @errortype
+ * @moduleid AMEC_HEALTH_CHECK_PROC_TEMP
+ * @reasoncode PROC_ERROR_TEMP
+ * @userdata1 0
+ * @userdata2 Fru peak temperature sensor
+ * @devdesc Processor FRU has reached error temperature
+ * threshold and is called out in this error log.
+ *
+ */
+ l_err = createErrl(AMEC_HEALTH_CHECK_PROC_TEMP,
+ PROC_ERROR_TEMP,
+ ERC_AMEC_PROC_ERROR_OVER_TEMPERATURE,
+ ERRL_SEV_PREDICTIVE,
+ NULL,
+ DEFAULT_TRACE_SIZE,
+ 0,
+ l_sensor->sample_max);
+
+ // Callout the Ambient procedure
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_OVER_TEMPERATURE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ // Callout to processor
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.proc_huid,
+ ERRL_CALLOUT_PRIORITY_MED);
+
+ // Commit Error
+ commitErrl(&l_err);
+ }
+ }
+ else
+ {
+ // Trace that we have now dropped below the error threshold
+ if (l_error_count >= AMEC_HEALTH_ERROR_TIMER)
+ {
+ TRAC_INFO("amec_health_check_proc_temp: We have dropped below error threshold for processors. error_count[%u]",
+ l_error_count);
+ }
+
+ // Reset the error counter for this FRU
+ l_error_count = 0;
+ }
+ }while (0);
+
+}
+
+// Function Specification
+//
+// Name: amec_health_check_proc_temp_timeout
+//
+// Description: This function checks if OCC has failed to read the processor
+// temperature and if it has exceeded the maximum allowed number of retries.
+//
+// End Function Specification
+void amec_health_check_proc_timeout()
+{
+
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ errlHndl_t l_err = NULL;
+ sensor_t *l_sensor = NULL;
+ BOOLEAN l_core_fail_detected = FALSE;
+ static uint32_t L_read_fail_cnt = 0;
+ uint8_t i = 0;
+ uint8_t l_bad_core_index = 0;
+ gpe_bulk_core_data_t *l_core_data_ptr = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ for(i=0; i<MAX_NUM_CORES; i++)
+ {
+ if(!CORE_PRESENT(i))
+ {
+ // If this core is not present, move on
+ continue;
+ }
+
+ // Check if this core's temperature sensor has been updated
+ l_sensor = AMECSENSOR_ARRAY_PTR(TEMP2MSP0C0,i);
+ if (l_sensor->update_tag == G_core_temp_update_tag[i])
+ {
+ // If the update tag is not changing, then this core's
+ // temperature sensor is not being updated.
+ l_core_fail_detected = TRUE;
+ l_bad_core_index = i;
+ }
+
+ // Take a snapshot of the update tag
+ G_core_temp_update_tag[i] = l_sensor->update_tag;
+ }
+
+ // Have we found at least one core that has reading failures?
+ if(!l_core_fail_detected)
+ {
+ // We were able to read all cores' temperature sensors so clear our
+ // counter
+ L_read_fail_cnt = 0;
+ }
+ else
+ {
+ // We've failed to read a core's temperature sensor so increment
+ // our counter
+ L_read_fail_cnt++;
+
+ // Check if we have reached the maximum read time allowed
+ if((L_read_fail_cnt == g_amec->thermalproc.temp_timeout) &&
+ (g_amec->thermalproc.temp_timeout != 0xFF))
+ {
+ TRAC_ERR("Timed out reading processor temperature on core_index[%u]",
+ l_bad_core_index);
+
+ // Get pointer to core data
+ l_core_data_ptr = proc_get_bulk_core_data_ptr(l_bad_core_index);
+
+ // Trace some critical registers to understand this error better
+ TRAC_ERR("OHA_Status_Reg[0x%08X] PM_State_Hist_Reg[0x%08X]",
+ l_core_data_ptr->oha.oha_ro_status_reg.words.low_order,
+ l_core_data_ptr->pcb_slave.pm_history.words.high_order);
+
+ TRAC_ERR("SensorV0[0x%08X%08X] SensorV1[0x%08X%08X]",
+ (uint32_t)(l_core_data_ptr->dts_cpm.sensors_v0.value >> 32),
+ (uint32_t)(l_core_data_ptr->dts_cpm.sensors_v0.value & 0x00000000ffffffffull),
+ (uint32_t)(l_core_data_ptr->dts_cpm.sensors_v1.value >> 32),
+ (uint32_t)(l_core_data_ptr->dts_cpm.sensors_v1.value & 0x00000000ffffffffull));
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_HEALTH_CHECK_PROC_TIMEOUT
+ * @reasoncode PROC_TEMP_TIMEOUT
+ * @userdata1 timeout value in seconds
+ * @userdata2 0
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Failed to read processor temperature.
+ *
+ */
+ l_err = createErrl(AMEC_HEALTH_CHECK_PROC_TIMEOUT, //modId
+ PROC_TEMP_TIMEOUT, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ g_amec->thermalproc.temp_timeout, //userdata1
+ 0); //userdata2
+
+ // Callout the processor
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.proc_huid,
+ ERRL_CALLOUT_PRIORITY_MED);
+
+ // Commit error log and request reset
+ REQUEST_RESET(l_err);
+ }
+ }
+ }while(0);
+}
+
+// Function Specification
+//
+// Name: amec_health_check_proc_vrhot
+//
+// Description: This function checks if VRHOT signal from processor regulator
+// has been asserted. The VRHOT signal is actually derived in firmware: if
+// VR_FAN signal is assserted and the 'fans_full_speed' GPIO is ON, then OCC
+// will considered VR_HOT as being asserted.
+//
+// End Function Specification
+void amec_health_check_proc_vrhot()
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ static BOOLEAN L_error_logged = FALSE;
+ sensor_t *l_sensor;
+ errlHndl_t l_err = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Get VRHOT50USPROC sensor
+ l_sensor = getSensorByGsid(VRHOT250USPROC);
+
+ // Check to see if we have exceeded our ERROR_COUNT
+ if(l_sensor->sample >= g_amec->vrhotproc.setpoint)
+ {
+ // We have reached the number of successive VRHOT samples allowed. Need
+ // to log an error (only once per OCC reset).
+ if(!L_error_logged)
+ {
+ L_error_logged = TRUE;
+
+ TRAC_ERR("amec_health_check_proc_vrhot: VRHOT has been asserted! num_samples[%u]",
+ l_sensor->sample);
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_HEALTH_CHECK_PROC_VRHOT
+ * @reasoncode VRM_ERROR_TEMP
+ * @userdata1 VRHOT error threshold
+ * @userdata2 0
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc VRHOT signal has been asserted long enough to
+ * exceed its error threshold.
+ *
+ */
+ l_err = createErrl(AMEC_HEALTH_CHECK_PROC_VRHOT,
+ VRM_ERROR_TEMP,
+ OCC_NO_EXTENDED_RC,
+ ERRL_SEV_PREDICTIVE,
+ NULL,
+ DEFAULT_TRACE_SIZE,
+ g_amec->vrhotproc.setpoint,
+ 0);
+
+ // Callout the Ambient procedure
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_OVER_TEMPERATURE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ // Callout backplane
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.backplane_huid,
+ ERRL_CALLOUT_PRIORITY_MED);
+
+ // Commit Error
+ commitErrl(&l_err);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_health.h b/src/occ_405/amec/amec_health.h
new file mode 100755
index 0000000..35271c0
--- /dev/null
+++ b/src/occ_405/amec/amec_health.h
@@ -0,0 +1,52 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_health.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 AMEC_HEALTH_H
+#define AMEC_HEALTH_H
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include "cmdh_fsp_cmds_datacnfg.h"
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+// Error threshold check is done every 16msec. Error timer is 5x16 = 80msec
+#define AMEC_HEALTH_ERROR_TIMER 5
+
+/*******************************************************************/
+/* Function Definitions */
+/*******************************************************************/
+
+void amec_health_check_proc_temp(void);
+void amec_health_check_proc_timeout(void);
+void amec_health_check_proc_vrhot();
+void amec_health_check_cent_temp(void);
+void amec_health_check_cent_timeout(void);
+void amec_health_check_dimm_temp(void);
+void amec_health_check_dimm_timeout(void);
+
+#endif
diff --git a/src/occ_405/amec/amec_init.c b/src/occ_405/amec/amec_init.c
new file mode 100644
index 0000000..487c9ef
--- /dev/null
+++ b/src/occ_405/amec/amec_init.c
@@ -0,0 +1,436 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_init.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 */
+
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <amec_sys.h>
+#include <ssx.h>
+#include <errl.h> // Error logging
+#include <rtls.h>
+#include <occ_sys_config.h>
+#include <occ_service_codes.h> // for SSX_GENERIC_FAILURE
+#include <trac.h>
+#include "state.h"
+#include "amec_service_codes.h"
+#include <amec_sys.h>
+#include <proc_data.h>
+#include <sensor.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+// We can initialize amec system structure to all zeros
+amec_sys_t g_amec_sys = {0};
+
+// Initialize g_amec to point to g_amec_sys
+// We use this pointer to keep the amec code as similar to previous projects
+amec_sys_t * g_amec = &g_amec_sys;
+
+// GPE Request Structure that is used to measure the worst case GPE timings
+PoreFlex G_gpe_nop_request[NUM_GPE_ENGINES];
+
+extern PoreEntryPoint GPE_pore_nop;
+extern void amec_slv_update_gpe_sensors(uint8_t i_gpe_engine);
+extern void amec_slv_update_gpe_sensors(uint8_t i_gpe_engine);
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+void amec_vectorize_core_sensor(sensor_t * l_sensor,
+ vectorSensor_t * l_vector,
+ const VECTOR_SENSOR_OP l_op,
+ uint16_t l_sensor_elem_array_gsid)
+{
+#define VECTOR_CREATE_FAILURE 1
+#define VECTOR_ADD_ELEM_FAILURE 2
+
+ int l_idx = 0; // Used to index the for loops for vector create
+ int l_rc = 0; // Indicates failure to add a sensor to vector
+ uint16_t l_gsid = 0xFFFF;
+ errlHndl_t l_err = NULL;
+
+ do
+ {
+ // Grab GSID for errl in case of failure
+ l_gsid = l_sensor->gsid;
+
+ // Vectorize the sensor
+ sensor_vectorize(l_sensor,
+ l_vector,
+ l_op);
+
+ // If vectorize worked, add elements to the vector sensor
+ if(NULL != l_sensor->vector)
+ {
+ // Loop through cores
+ for(l_idx = 0; l_idx < MAX_NUM_CORES; l_idx++)
+ {
+ // Add elements to the vector sensor
+ sensor_vector_elem_add(l_sensor->vector,
+ l_idx,
+ AMECSENSOR_ARRAY_PTR(l_sensor_elem_array_gsid, l_idx));
+ // If core is not present, disable this vector element
+ if(!CORE_PRESENT(l_idx))
+ {
+ sensor_vector_elem_enable(l_sensor->vector,
+ l_idx,
+ 0 /* Disable */);
+ }
+ }
+
+ // Sanity check, we should have MAX_NUM_CORES entries in
+ // vector sensor
+ if(l_sensor->vector->size != MAX_NUM_CORES)
+ {
+ // Set l_rc and break out so that we can create an errl
+ l_rc = VECTOR_ADD_ELEM_FAILURE;
+ break;
+ }
+ }
+ else
+ {
+ // Set l_rc and break out so that we can create an errl
+ l_rc = VECTOR_CREATE_FAILURE;
+ break;
+ }
+ }while(0);
+
+ if(l_rc)
+ {
+ //If fail to create pore flex object then there is a problem.
+ TRAC_ERR("Failed to vectorize sensor[0x%x, 0x%x]", l_gsid, l_rc );
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_VECTORIZE_FW_SENSORS
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 return code
+ * @userdata2 gsid of failed sensor
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Firmware failure in call to vectorize sensor
+ */
+ l_err = createErrl(
+ AMEC_VECTORIZE_FW_SENSORS, //modId
+ SSX_GENERIC_FAILURE, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL,//TODO: create trace //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_rc, //userdata1
+ l_gsid //userdata2
+ );
+
+ REQUEST_RESET(l_err);
+ }
+}
+
+void amec_init_vector_sensors(void)
+{
+
+#define VECTOR_CREATE_FAILURE 1
+#define VECTOR_ADD_ELEM_FAILURE 2
+
+ //-----------------------------------------------------
+ // TEMP2MSP0 Vector Sensor
+ //-----------------------------------------------------
+ amec_vectorize_core_sensor(AMECSENSOR_PTR(TEMP2MSP0),
+ &g_amec_sys.proc[0].temp2ms_vector,
+ VECTOR_OP_AVG,
+ TEMP2MSP0C0);
+
+ //-----------------------------------------------------
+ // FREQA2MSP0 Vector Sensor
+ //-----------------------------------------------------
+ amec_vectorize_core_sensor(AMECSENSOR_PTR(FREQA2MSP0),
+ &g_amec_sys.proc[0].freqa2ms_vector,
+ VECTOR_OP_AVG,
+ FREQA2MSP0C0);
+
+ //-----------------------------------------------------
+ // IPS2MSP0 Vector Sensor
+ //-----------------------------------------------------
+ amec_vectorize_core_sensor(AMECSENSOR_PTR(IPS2MSP0),
+ &g_amec_sys.proc[0].ips2ms_vector,
+ VECTOR_OP_AVG,
+ IPS2MSP0C0);
+
+ //-----------------------------------------------------
+ // TEMP2MSP0PEAK Vector Sensor
+ //-----------------------------------------------------
+ amec_vectorize_core_sensor(AMECSENSOR_PTR(TEMP2MSP0PEAK),
+ &g_amec_sys.proc[0].temp2mspeak_vector,
+ VECTOR_OP_MAX,
+ TEMP2MSP0C0);
+
+ //-----------------------------------------------------
+ // UTIL2MSP0 Vector Sensor
+ //-----------------------------------------------------
+ amec_vectorize_core_sensor(AMECSENSOR_PTR(UTIL2MSP0),
+ &g_amec_sys.proc[0].util2ms_vector,
+ VECTOR_OP_AVG,
+ UTIL2MSP0C0);
+
+//TODO: Re-enable with error checking when centaur support is added
+#if 0
+ int l_rc = 0, l_idx = 0, l_idx2 = 0; // Used to index the for loops for vector create
+ //-----------------------------------------------------
+ // MEMSP2MSP0 Vector Sensor
+ //-----------------------------------------------------
+ sensor_vectorize(AMECSENSOR_PTR(MEMSP2MSP0),
+ &g_amec_sys.proc[0].memsp2ms_vector,
+ VECTOR_OP_MIN);
+
+ for(l_idx=0; l_idx<MAX_NUM_MEM_CONTROLLERS; l_idx++)
+ {
+ for(l_idx2=0; l_idx2<NUM_PORT_PAIRS_PER_CENTAUR; l_idx2++)
+ {
+ sensor_vector_elem_add(AMECSENSOR_PTR(MEMSP2MSP0)->vector,
+ l_idx,
+ AMECSENSOR_2D_ARRAY_PTR(MEMSP2MSPM0C0P0,l_idx, l_idx2));
+ }
+ }
+#endif
+}
+
+// Function Specification
+//
+// Name: amec_init_gamec_struct
+//
+// Description: Perform initialization of g_amec structure
+//
+// End Function Specification
+void amec_init_gamec_struct(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_idx = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Defaul the frequency range to something safe
+ g_amec->sys.fmin = 2000;
+ g_amec->sys.fmax = 2000;
+ g_amec->sys.max_speed = 1000;
+
+ g_amec->sys.min_speed = 400;
+ g_amec->sys.speed_step = 10;
+ g_amec->sys.speed_step_limit = (uint16_t)((65535/4)/(g_amec->sys.speed_step));
+
+ // Initialize thermal controller for processor
+ g_amec->thermalproc.setpoint = 850; // change to 850 = 85.0 C
+ g_amec->thermalproc.Pgain = 1000;
+ g_amec->thermalproc.speed_request = 1000;
+ g_amec->thermalproc.freq_request = -1; //unconstrained frequency vote
+ g_amec->thermalproc.total_res = 0;
+
+ // Initialize thermal controller based on DIMM temperatures
+ g_amec->thermaldimm.setpoint = 850; //In 0.1 degrees C -> 850 = 85.0 C
+ g_amec->thermaldimm.Pgain = 30000;
+ g_amec->thermaldimm.speed_request = AMEC_MEMORY_MAX_STEP;
+
+ // Initialize thermal controller based on Centaur temperatures
+ g_amec->thermalcent.setpoint = 850; //In 0.1 degrees C -> 850 = 85.0 C
+ g_amec->thermalcent.Pgain = 30000;
+ g_amec->thermalcent.speed_request = AMEC_MEMORY_MAX_STEP;
+
+ // Initialize controler based on VRHOT signal from processor regulator
+ g_amec->vrhotproc.setpoint = 100;
+ g_amec->vrhotproc.freq_request = -1;
+ g_amec->vrhotproc.speed_request = 1000;
+
+ // Initialize partition information
+ amec_part_init();
+
+ // Initialize performace counter
+ for (l_idx=0; l_idx<MAX_NUM_CORES; l_idx++)
+ {
+ amec_core_perf_counter_ctor(&g_amec->proc[0].core[l_idx].core_perf, 0, l_idx);
+ }
+
+ //Initialize processor fields
+ g_amec->proc[0].core_max_freq = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
+
+ //Initialize processor power votes
+ g_amec->proc[0].pwr_votes.pmax_clip_freq = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
+ g_amec->proc[0].pwr_votes.apss_pmax_clip_freq = 0xFFFF;
+
+ //Initialize stream buffer recording parameters
+ g_amec->recordflag=0; // Never enable recording until requested via Amester API call
+ g_amec->r_cnt=0; // Reset counter of 250us ticks
+ g_amec->ptr_stream_buffer = &g_amec->stream_buffer[0];
+ g_amec->stream_vector_mode=0; // No recording yet
+ g_amec->stream_vector_delay=0; // Delay in msec before recording can begin
+ g_amec->stream_vector_rate=0xff; // Invalid setting: requires IPMI command to select initial rate
+
+ //Initialize analytics parameters
+ g_amec->analytics_group=45; // Default to analytics Group 45
+ g_amec->analytics_chip=0; // Default to which chip to perform analytics on
+ g_amec->analytics_bad_output_count=0; // Number of frames to discard before recording analytics output
+ g_amec->analytics_total_chips=MAX_NUM_CHIP_MODULES; // Default to do all chips in the system
+ g_amec->analytics_threadmode=1; // Default is average of all N threads (may be altered with IPMI command)
+ g_amec->analytics_threadcountmax=8;// Default is 8 threads per core (may be altered with IPMI command)
+ g_amec->analytics_total_chips=4; // For Tuleta force to only 2 DCM sockets, 4 chips
+ g_amec->analytics_option=1; // =0 means cycle through all chips, =1 means only work with analytics_chip
+ g_amec->analytics_thermal_offset=0;// Reset offset to 0 for thermal output group
+ g_amec->analytics_slot=4; // Time slot associated with when the amec_analytics function is called (out of 8 slots)
+ // Set entire averaging buffer to zero
+ memset (&g_amec->g44_avg, 0, 4*(MAX_SENSORS_ANALYTICS*MAX_NUM_CHIP_MODULES));
+ for(l_idx=0; l_idx<NUM_AMEC_FW_PROBES; l_idx++)
+ {
+ g_amec->ptr_probe250us[l_idx] = &g_amec->sys.pwr250us.sample;
+ g_amec->size_probe250us[l_idx] = 2; // Size of object pointed to by probe is 2 bytes
+ g_amec->index_probe250us[l_idx] = 0; // Initialize all offsets to 0 (used only if size > 2)
+ }
+
+// g_amec->ptr_probe250us[1] = g_amec->proc[0].sleepcnt2ms.sample;
+// g_amec->ptr_probe250us[2] = &g_amec->g44_avg[(0*MSA)+49];
+// g_amec->ptr_probe250us[2] = g_amec->ptr_probe250us[2]+2; // Point to low 16 bits of g44_avg
+// g_amec->ptr_probe250us[3] = &g_amec->proc[0].core[0].thread[0].util2ms_thread;
+ g_amec->ptr_probe250us[1] = &g_amec->sys.pwr250us.sample;
+ g_amec->ptr_probe250us[2] = &g_amec->r_cnt;
+ g_amec->ptr_probe250us[2] = g_amec->ptr_probe250us[2]+2; // Point to low 16 bits of r_cnt
+ g_amec->ptr_probe250us[3] = &g_amec->r_cnt;
+// g_amec->ptr_probe250us[4] = &g_amec->testscom1;
+// g_amec->ptr_probe250us[5] = &g_amec->traffic_delay; // holds loop delay for holding up memory traffic
+// g_amec->ptr_probe250us[6] = &g_amec->testscom1;
+// g_amec->ptr_probe250us[6] = g_amec->ptr_probe250us[6]+2; // Point to low 16 bits of testscom1
+// g_amec->ptr_probe250us[7] = &g_amec->task_centaur_data_count;
+
+}
+
+// Function Specification
+//
+// Name: amec_slave_init
+//
+// Description: Perform initialization of any/all AMEC Slave Functions
+//
+// End Function Specification
+void amec_slave_init()
+{
+ errlHndl_t l_err = NULL; // Error handler
+ int rc = 0; // Return code
+ int rc2 = 0; // Return code
+
+ // Set the GPE Request Pointers to NULL in case the create fails.
+ G_fw_timing.gpe0_timing_request = NULL;
+ G_fw_timing.gpe1_timing_request = NULL;
+
+ // Initializes the GPE routine that will be used to measure the worst case
+ // timings for GPE0
+ rc = pore_flex_create( &G_gpe_nop_request[0], //gpe_req for the task
+ &G_pore_gpe0_queue, //queue
+ (void *) GPE_pore_nop, //entry point
+ (uint32_t) NULL, //parm for the task
+ SSX_WAIT_FOREVER, //no timeout
+ (AsyncRequestCallback) amec_slv_update_gpe_sensors, //callback
+ (void *) GPE_ENGINE_0, //callback argument
+ ASYNC_CALLBACK_IMMEDIATE ); //options
+
+ // Initializes the GPE routine that will be used to measure the worst case
+ // timings for GPE1
+ rc2 = pore_flex_create( &G_gpe_nop_request[1], //gpe_req for the task
+ &G_pore_gpe1_queue, //queue
+ (void *)GPE_pore_nop, //entry point
+ (uint32_t) NULL, //parm for the task
+ SSX_WAIT_FOREVER, //no timeout
+ (AsyncRequestCallback) amec_slv_update_gpe_sensors, //callback
+ (void *) GPE_ENGINE_1, //callback argument
+ ASYNC_CALLBACK_IMMEDIATE ); //options
+
+ // If we couldn't create the poreFlex objects, there must be a major problem
+ // so we will log an error and halt OCC.
+ if( rc || rc2 )
+ {
+ //If fail to create pore flex object then there is a problem.
+ TRAC_ERR("Failed to create GPE duration poreFlex object[0x%x, 0x%x]", rc, rc2 );
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_INITIALIZE_FW_SENSORS
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 return code - gpe0
+ * @userdata2 return code - gpe1
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Failure to create PORE-GPE poreFlex object for FW timing
+ * analysis.
+ *
+ */
+ l_err = createErrl(
+ AMEC_INITIALIZE_FW_SENSORS, //modId
+ SSX_GENERIC_FAILURE, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //TODO: create trace //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ rc, //userdata1
+ rc2 //userdata2
+ );
+
+ REQUEST_RESET(l_err);
+ }
+ else
+ {
+ // Everything was successful, so set FW timing pointers to these
+ // GPE Request objects
+ G_fw_timing.gpe0_timing_request = &G_gpe_nop_request[0];
+ G_fw_timing.gpe1_timing_request = &G_gpe_nop_request[1];
+ }
+
+ // Initialize Vector Sensors for AMEC use
+ amec_init_vector_sensors();
+
+ // Initialize AMEC internal parameters
+ amec_init_gamec_struct();
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_master_smh.c b/src/occ_405/amec/amec_master_smh.c
new file mode 100755
index 0000000..c49ca06
--- /dev/null
+++ b/src/occ_405/amec/amec_master_smh.c
@@ -0,0 +1,1076 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_master_smh.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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include <errl.h> // Error logging
+#include "rtls.h"
+#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE
+#include "sensor.h"
+#include "amec_smh.h"
+#include "amec_master_smh.h"
+#include <trac.h> // For traces
+#include "amec_sys.h"
+#include "amec_service_codes.h" //For AMEC_MST_CHECK_PCAPS_MATCH
+#include "dcom.h"
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//Power cap mismatch threshold set to 8 ticks (2 milliseconds)
+#define PCAPS_MISMATCH_THRESHOLD 8
+
+//Power cap failure threshold set to 32 (ticks)
+#define PCAP_FAILURE_THRESHOLD 32
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+smh_state_t G_amec_mst_state = {AMEC_INITIAL_STATE,
+ AMEC_INITIAL_STATE,
+ AMEC_INITIAL_STATE};
+
+//Array that stores active power cap values of all OCCs
+slave_pcap_info_t G_slave_active_pcaps[MAX_OCCS] = {{0}};
+
+//OCC Power cap mismatch count
+uint8_t G_pcaps_mismatch_count = 0;
+
+//OCC over power cap count
+uint8_t G_over_cap_count = 0;
+
+//Array that stores the exit counts for the IPS algorithm
+uint32_t G_ips_exit_count[MAX_OCCS][MAX_CORES] = {{0}};
+//Array that stores the entry counts for the IPS algorithm
+uint32_t G_ips_entry_count = 0;
+
+//Soft Fmin to be sent to Slave OCCs
+uint16_t G_mst_soft_fmin = 0;
+//Soft Fmax to be sent to Slave OCCs
+uint16_t G_mst_soft_fmax = 0xFFFF;
+//Counter of committed violations by the Slave OCCs
+uint8_t G_mst_violation_cnt[MAX_OCCS] = {0};
+
+// --------------------------------------------------------
+// AMEC Master State 6.1 Substate Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 128ms.
+//
+const smh_tbl_t amec_mst_state_6_1_sub_substate_table[AMEC_SMH_STATES_PER_LVL] =
+{
+ {amec_mst_sub_substate_6_1_0, NULL},
+ {amec_mst_sub_substate_6_1_1, NULL},
+ {amec_mst_sub_substate_6_1_2, NULL},
+ {amec_mst_sub_substate_6_1_3, NULL},
+ {amec_mst_sub_substate_6_1_4, NULL},
+ {amec_mst_sub_substate_6_1_5, NULL},
+ {amec_mst_sub_substate_6_1_6, NULL},
+ {amec_mst_sub_substate_6_1_7, NULL},
+};
+
+// --------------------------------------------------------
+// AMEC Master State 0 Substate Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 16ms.
+//
+// The 2 States are interleaved so each one runs every 4ms.
+//
+const smh_tbl_t amec_mst_state_0_substate_table[AMEC_SMH_STATES_PER_LVL] =
+{
+ {amec_mst_substate_0_0, NULL},
+ {amec_mst_substate_0_1, NULL},
+ {amec_mst_substate_0_0, NULL},
+ {amec_mst_substate_0_1, NULL},
+ {amec_mst_substate_0_0, NULL},
+ {amec_mst_substate_0_1, NULL},
+ {amec_mst_substate_0_0, NULL},
+ {amec_mst_substate_0_1, NULL},
+};
+
+// --------------------------------------------------------
+// AMEC Master State 3 Substate Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 16ms.
+//
+// The 2 States are interleaved so each one runs every 4ms.
+//
+const smh_tbl_t amec_mst_state_3_substate_table[AMEC_SMH_STATES_PER_LVL] =
+
+{
+ {amec_mst_substate_3_0, NULL},
+ {amec_mst_substate_3_1, NULL},
+ {amec_mst_substate_3_0, NULL},
+ {amec_mst_substate_3_1, NULL},
+ {amec_mst_substate_3_0, NULL},
+ {amec_mst_substate_3_1, NULL},
+ {amec_mst_substate_3_0, NULL},
+ {amec_mst_substate_3_1, NULL},
+};
+
+// --------------------------------------------------------
+// AMEC Master State 6 Substate Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 16ms.
+//
+// SubState1: 8 Sub-substates (128ms/sub-substate)
+//
+const smh_tbl_t amec_mst_state_6_substate_table[AMEC_SMH_STATES_PER_LVL] =
+{
+ {amec_mst_substate_6_0, NULL},
+ {amec_mst_substate_6_1, amec_mst_state_6_1_sub_substate_table},
+ {amec_mst_substate_6_2, NULL},
+ {amec_mst_substate_6_3, NULL},
+ {amec_mst_substate_6_4, NULL},
+ {amec_mst_substate_6_5, NULL},
+ {amec_mst_substate_6_6, NULL},
+ {amec_mst_substate_6_7, NULL},
+};
+
+// --------------------------------------------------------
+// Main AMEC Master State Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 2ms.
+//
+// State0: 2 Substates (4ms/substate)
+// State3: 2 Substates (4ms/substate)
+// State6: 8 Substates (16ms/substate)
+//
+const smh_tbl_t amec_mst_state_table[AMEC_SMH_STATES_PER_LVL] =
+{
+ {amec_mst_state_0, amec_mst_state_0_substate_table},
+ {amec_mst_state_1, NULL},
+ {amec_mst_state_2, NULL},
+ {amec_mst_state_3, amec_mst_state_3_substate_table},
+ {amec_mst_state_4, NULL},
+ {amec_mst_state_5, NULL},
+ {amec_mst_state_6, amec_mst_state_6_substate_table},
+ {amec_mst_state_7, NULL},
+};
+
+// This sets up the function pointer that will be called to update the
+// fw timings when the AMEC master State Machine finishes.
+smh_state_timing_t G_amec_mst_state_timings = {amec_mst_update_smh_sensors};
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// Function Specification
+//
+// Name: amec_mst_update_smh_sensors
+//
+// Description: Update the sensor
+//
+// End Function Specification
+void amec_mst_update_smh_sensors(int i_smh_state, uint32_t i_duration)
+{
+ // Update the duration in the fw timing table
+ if(G_fw_timing.amess_state != i_smh_state)
+ {
+ AMEC_DBG("Mismatch between Master and Slave AMEC states\n");
+ }
+
+ G_fw_timing.amess_dur += i_duration;
+}
+
+// Function Specification
+//
+// Name: amec_master_auto_slew
+//
+// Description: This function executes the auto-slewing of frequency based on
+// manufacturing parameters.
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_master_auto_slew(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ static int8_t l_direction = 1;
+ uint16_t l_freq = 0;
+ static uint16_t l_step_delay = 0;
+ static bool l_first_time_enable = TRUE;
+ static bool l_first_time_disable = FALSE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ // Check if auto-slewing has been enabled
+ if (g_amec->mnfg_parms.auto_slew)
+ {
+ // Is this the first time we are enabling auto-slewing?
+ if (l_first_time_enable)
+ {
+ // Need to start the auto-slew from fmax
+ g_amec->mnfg_parms.foverride = g_amec->mnfg_parms.fmax;
+
+ // Reset the delay counter and reset the direction
+ l_step_delay = g_amec->mnfg_parms.delay;
+ l_direction = 1;
+
+ l_first_time_enable = FALSE;
+ l_first_time_disable = TRUE;
+
+ // Break out now to give it some time to get to fmax
+ break;
+ }
+ }
+ else
+ {
+ // Is this the first time we are disabling auto-slewing?
+ if (l_first_time_disable)
+ {
+ // Clear the frequency override parameter
+ g_amec->mnfg_parms.foverride = 0;
+
+ l_first_time_enable = TRUE;
+ l_first_time_disable = FALSE;
+ }
+
+ // We are done, break
+ break;
+ }
+
+ // If we've made it this far, then we are running auto-slew. First,
+ // check if our delay counter has expired.
+ if (l_step_delay != 0)
+ {
+ // Decrement our delay counter and exit
+ l_step_delay--;
+ break;
+ }
+
+ // Our delay counter has expired, reset it to its original value
+ l_step_delay = g_amec->mnfg_parms.delay;
+
+ // Now, generate a new frequency override
+ l_freq = g_amec->mnfg_parms.foverride -
+ (l_direction * g_amec->mnfg_parms.fstep);
+
+ if (l_freq <= g_amec->mnfg_parms.fmin)
+ {
+ // We've reached an edge, increment our counter
+ g_amec->mnfg_parms.slew_counter++;
+
+ // Change direction of the auto-slew
+ l_direction = -l_direction;
+
+ // Clip frequency to fmin
+ l_freq = g_amec->mnfg_parms.fmin;
+ }
+ else if (l_freq >= g_amec->mnfg_parms.fmax)
+ {
+ // We've reached an edge, increment our counter
+ g_amec->mnfg_parms.slew_counter++;
+
+ // Change direction of the auto-slew
+ l_direction = -l_direction;
+
+ // Clip frequency to fmax
+ l_freq = g_amec->mnfg_parms.fmax;
+ }
+ g_amec->mnfg_parms.foverride = l_freq;
+
+ }while(0);
+
+ return;
+}
+
+// Function Specification
+//
+// Name: amec_mst_check_pcaps_match
+//
+// Description: This function checks for mismatch in power caps between
+// occs for 8 consecutive ticks.
+//
+// End Function Specification
+void amec_mst_check_pcaps_match(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint8_t l_chip_id;
+ bool l_prev_pcap_valid = FALSE;
+ uint16_t l_prev_pcap = 0;
+ bool l_pcap_mismatch = FALSE;
+ errlHndl_t l_err = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ //Loop through all occs
+ for(l_chip_id = 0; l_chip_id < MAX_OCCS; l_chip_id++)
+ {
+ //if occ is present && its pcap data is considered valid
+ if((G_sysConfigData.is_occ_present & (1<< l_chip_id)) &&
+ (G_slave_active_pcaps[l_chip_id].pcap_valid != 0))
+ {
+ //TRAC_INFO(" occ[%d]: pcap[%d] valid(%d)",
+ // l_chip_id, G_slave_active_pcaps[l_chip_id].active_pcap, G_slave_active_pcaps[l_chip_id].pcap_valid );
+
+ //Initialize l_prev_pcap to the first valid/present occ's power cap
+ if(!l_prev_pcap_valid)
+ {
+ //TRAC_INFO("First present occ - power cap info[%d]=%d(%d)",
+ // l_chip_id, G_slave_active_pcaps[l_chip_id].active_pcap, G_slave_active_pcaps[l_chip_id].pcap_valid );
+
+ l_prev_pcap = G_slave_active_pcaps[l_chip_id].active_pcap;
+ l_prev_pcap_valid = TRUE;
+ }
+ else
+ {
+ //If there is mismatch between OCCs power caps, increment mismatch
+ // count
+ if(l_prev_pcap != G_slave_active_pcaps[l_chip_id].active_pcap)
+ {
+ G_pcaps_mismatch_count++;
+ l_pcap_mismatch = TRUE;
+
+ TRAC_INFO("Mismatch in OCC power cap values: mismatch cnt=%d pcap=%d vs compared pcap[%d]=%d(%d)",
+ G_pcaps_mismatch_count, l_prev_pcap, l_chip_id, G_slave_active_pcaps[l_chip_id].active_pcap,
+ G_slave_active_pcaps[l_chip_id].pcap_valid);
+
+ //If mismatch occurs for 8 consecutive ticks
+ //i.e 8 * 250 microsecs = 2 milliseconds,then reset occ
+ if(G_pcaps_mismatch_count >= PCAPS_MISMATCH_THRESHOLD)
+ {
+ TRAC_ERR("Mismatch in OCC power cap values: pcap=%d, slave_active_pcap[%d]=%d(%d)",
+ l_prev_pcap, l_chip_id, G_slave_active_pcaps[l_chip_id].active_pcap,
+ G_slave_active_pcaps[l_chip_id].pcap_valid);
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_MST_CHECK_PCAPS_MATCH
+ * @reasoncode INTERNAL_FAILURE
+ * @userdata1 First OCC Power cap
+ * @userdata2 Mismatch OCC Power cap
+ * @devdesc Internal max power limits mismatched
+ *
+ */
+ l_err = createErrl( AMEC_MST_CHECK_PCAPS_MATCH,
+ INTERNAL_FAILURE,
+ ERC_AMEC_PCAPS_MISMATCH_FAILURE,
+ ERRL_SEV_PREDICTIVE,
+ NULL,
+ DEFAULT_TRACE_SIZE,
+ l_prev_pcap,
+ G_slave_active_pcaps[l_chip_id].active_pcap);
+
+ //Callout to OVS
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ //Callout to APSS
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.apss_huid,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ //Callout to DPSS
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.dpss_huid,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+ //Reset OCC
+ REQUEST_RESET(l_err);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ //If there was no power cap mismatch between occ's,then reset count to zero
+ if(!l_pcap_mismatch)
+ {
+ G_pcaps_mismatch_count = 0;
+ }
+}
+
+
+// Function Specification
+//
+// Name: amec_mst_check_under_pcap
+//
+// Description: This function checks if there is failure in maintaining power
+// cap value.
+//
+// End Function Specification
+
+void amec_mst_check_under_pcap(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ errlHndl_t l_err = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Check if ppb_fmax = Fmin and PWR250US > Node power cap and
+ // Node power cap >= hard_min_pcap
+ if((g_amec->proc[0].pwr_votes.ppb_fmax == g_amec->sys.fmin) &&
+ (AMECSENSOR_PTR(PWR250US)->sample > g_amec->pcap.active_node_pcap) &&
+ (g_amec->pcap.active_node_pcap >= G_sysConfigData.pcap.hard_min_pcap))
+ {
+
+ G_over_cap_count++;
+
+ //Log error and reset OCC if count >= 32 (ticks)
+ if(G_over_cap_count >= PCAP_FAILURE_THRESHOLD)
+ {
+ TRAC_ERR("Failure to maintain power cap: Power Cap = %d ,"
+ "PWR250US = %d ,PWR250USP0 = %d ,PWR250USFAN = %d ,"
+ "PWR250USMEM0 = %d",g_amec->pcap.active_node_pcap,
+ AMECSENSOR_PTR(PWR250US)->sample,
+ AMECSENSOR_PTR(PWR250USP0)->sample,
+ AMECSENSOR_PTR(PWR250USFAN)->sample,
+ AMECSENSOR_PTR(PWR250USMEM0)->sample);
+
+ TRAC_ERR("PWR250USIO = %d , PWR250USSTORE = %d, PWR250USGPU = %d",
+ AMECSENSOR_PTR(PWR250USIO)->sample,
+ AMECSENSOR_PTR(PWR250USSTORE)->sample,
+ AMECSENSOR_PTR(PWR250USGPU)->sample);
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_MST_CHECK_UNDER_PCAP
+ * @reasoncode POWER_CAP_FAILURE
+ * @userdata1 Power Cap
+ * @userdata2 PWR250US (Node Power)
+ * @devdesc Failure to maintain max power limits
+ *
+ */
+ l_err = createErrl( AMEC_MST_CHECK_UNDER_PCAP,
+ POWER_CAP_FAILURE,
+ ERC_AMEC_UNDER_PCAP_FAILURE,
+ ERRL_SEV_PREDICTIVE,
+ NULL,
+ DEFAULT_TRACE_SIZE,
+ g_amec->pcap.active_node_pcap,
+ AMECSENSOR_PTR(PWR250US)->sample);
+
+ //Callout to firmware
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ //Callout to APSS
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.apss_huid,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ //Reset OCC
+ REQUEST_RESET(l_err);
+ }
+ }
+ else
+ {
+ //Decrement count if node power under power cap value
+ if(G_over_cap_count > 0)
+ {
+ G_over_cap_count--;
+ }
+ }
+
+ return;
+}
+
+// Function Specification
+//
+// Name: amec_mst_ips_main
+//
+// Description: This function executes the Idle Power Saver (IPS)
+// algorithm.
+//
+// End Function Specification
+void amec_mst_ips_main(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t i = 0;
+ uint16_t j = 0;
+ uint16_t l_time_interval = 0;
+ uint16_t l_core_count = 0;
+ uint16_t l_entry_core_count = 0;
+ BOOLEAN l_exit = FALSE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ // If IPS is disabled, no need to execute the algorithm
+ if (g_amec->mst_ips_parms.enable == 0)
+ {
+ // Reset the following parameters
+ g_amec->mst_ips_parms.active = 0;
+ G_ips_entry_count = 0;
+ g_amec->mst_ips_parms.freq_request = g_amec->sys.fmax;
+
+ break;
+ }
+
+ // We made it here, so that means IPS is enabled.
+ l_time_interval = AMEC_DPS_SAMPLING_RATE * AMEC_IPS_AVRG_INTERVAL;
+
+ // If IPS is active, check if the exit criteria has been met
+ if (g_amec->mst_ips_parms.active == 1)
+ {
+ // Useful trace for debugging
+ //TRAC_INFO("DBG_IPS: IPS is active! exit_countp0c5[%u]",
+ // G_ips_exit_count[0][5]);
+
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ if (!(G_sysConfigData.is_occ_present & (1<<i)))
+ {
+ // This OCC is not present, just move along
+ continue;
+ }
+
+ for (j=0; j<MAX_CORES; j++)
+ {
+ // Check if this core's normalized utilization has exceeded
+ // the exit threshold
+ if (G_dcom_slv_outbox_rx[i].nutil3sp0cy[j] >=
+ g_amec->mst_ips_parms.exit_threshold)
+ {
+ // Increment our exit count by the number of samples
+ // used to average utilization (default is 3 seconds)
+ G_ips_exit_count[i][j] += l_time_interval;
+
+ if (G_ips_exit_count[i][j] >=
+ g_amec->mst_ips_parms.exit_delay)
+ {
+ // Found one core that meets the exit criteria!
+ l_exit = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ // If the normalized utilization of this core is below
+ // the exit threshold, reset its exit count
+ G_ips_exit_count[i][j] = 0;
+ }
+ }
+
+ if (l_exit)
+ {
+ break;
+ }
+ }
+
+ // If we found a core that meets the exit criteria, then exit IPS
+ // active state
+ if (l_exit)
+ {
+ g_amec->mst_ips_parms.active = 0;
+ G_ips_entry_count = 0;
+ // A special request of 0 frequency will inform the slaves to
+ // ignore the IPS request from the master
+ g_amec->mst_ips_parms.freq_request = 0;
+
+ TRAC_INFO("amec_mst_ips_main: We have exited IPS active state! exit_count[%u] freq_request[%u]",
+ G_ips_exit_count[i][j], g_amec->mst_ips_parms.freq_request);
+ }
+ }
+ else //IPS is inactive, check if entry criteria has been met
+ {
+ // Useful trace for debugging
+ //TRAC_INFO("DBG_IPS: IPS is inactive! entry_count[%u]",
+ // G_ips_entry_count);
+
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ if (!(G_sysConfigData.is_occ_present & (1<<i)))
+ {
+ // This OCC is not present, just move along
+ continue;
+ }
+
+ for (j=0; j<MAX_CORES; j++)
+ {
+ l_core_count++;
+
+ // Note: cores that are not present will return a zero
+ // utilization, thus fulfilling the check below
+ if (G_dcom_slv_outbox_rx[i].nutil3sp0cy[j] <
+ g_amec->mst_ips_parms.entry_threshold)
+ {
+ // Count how many cores have a normalized utilization
+ // below the entry threshold
+ l_entry_core_count++;
+ }
+ else
+ {
+ // Reset the entry count since we found a core that
+ // has a utilization >= entry threshold
+ G_ips_entry_count = 0;
+ }
+ }
+ }
+
+ // All cores have a utilization lower than the entry threshold
+ if (l_entry_core_count == l_core_count)
+ {
+ // Increment the entry count by the number of samples used to
+ // average utilization (default is 3 seconds)
+ G_ips_entry_count += l_time_interval;
+
+ if (G_ips_entry_count >= g_amec->mst_ips_parms.entry_delay)
+ {
+ // We have met the entry criteria, move IPS state to active
+ g_amec->mst_ips_parms.active = 1;
+
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ if (!(G_sysConfigData.is_occ_present & (1<<i)))
+ {
+ continue;
+ }
+ for (j=0; j<MAX_CORES; j++)
+ {
+ G_ips_exit_count[i][j] = 0;
+ }
+ }
+
+ g_amec->mst_ips_parms.freq_request =
+ G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+
+ TRAC_INFO("amec_mst_ips_main: We have entered IPS active state! entry_count[%u] freq_request[%u]",
+ G_ips_entry_count, g_amec->mst_ips_parms.freq_request);
+ }
+ }
+ }
+ }while(0);
+}
+
+uint8_t AMEC_mst_get_ips_active_status()
+{
+ return g_amec->mst_ips_parms.active;
+}
+
+// Function Specification
+//
+// Name: amec_mst_gen_soft_freq
+//
+// Description: This function executes the algorithm that generates the soft
+// frequency boundaries to be sent to the Slave OCCs. This is the strategy
+// to be used for P8 GA1.
+//
+// End Function Specification
+void amec_mst_gen_soft_freq(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint8_t i = 0;
+ uint16_t l_ftarget = 0;
+ uint16_t l_fdelta = 0;
+ uint16_t l_lowest_fwish = 0;
+ uint16_t l_highest_fwish = 0;
+ BOOLEAN l_need_reset = FALSE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ do
+ {
+ // First, check if frequency delta has been enabled
+ if (G_mst_tunable_parameter_table_ext[7].adj_value == 0)
+ {
+ // If it hasn't been enabled, then use the full frequency range and
+ // break
+ G_mst_soft_fmin = 0x0000;
+ G_mst_soft_fmax = 0xFFFF;
+
+ break;
+ }
+
+ // Use the frequency delta sent by the customer
+ l_fdelta = (G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL] *
+ G_mst_tunable_parameter_table_ext[8].adj_value/2) / 100;
+
+ // Check if all OCCs are operating inside the soft frequency boundaries
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ // Ignore OCCs that are sending zeros for factual or fwish
+ if ((G_dcom_slv_outbox_rx[i].factual == 0) ||
+ (G_dcom_slv_outbox_rx[i].fwish == 0))
+ {
+ continue;
+ }
+
+ // Compare factual against the soft frequency boundaries
+ if ((G_dcom_slv_outbox_rx[i].factual < G_mst_soft_fmin) ||
+ (G_dcom_slv_outbox_rx[i].factual > G_mst_soft_fmax))
+ {
+ G_mst_violation_cnt[i]++;
+ }
+ else
+ {
+ G_mst_violation_cnt[i] = 0;
+ }
+
+ // Now check if the violation count has exceeded the threshold
+ if (G_mst_violation_cnt[i] > 3)
+ {
+ // The new target frequency is the violator's factual
+ l_need_reset = TRUE;
+ l_ftarget = G_dcom_slv_outbox_rx[i].factual;
+ }
+ }
+
+ // If all OCCs are inside the soft frequency boundaries, select the
+ // target frequeny based on the power mode
+ if (!l_need_reset)
+ {
+ if ((CURRENT_MODE() == OCC_MODE_DYN_POWER_SAVE) ||
+ (CURRENT_MODE() == OCC_MODE_DYN_POWER_SAVE_FP))
+ {
+ // For DPS and DPS-FP modes, calculate the highest Fwish sent
+ // by all slave OCCs
+ l_highest_fwish = 0;
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ // Ignore OCCs that are sending zeros for factual or fwish
+ if ((G_dcom_slv_outbox_rx[i].factual == 0) ||
+ (G_dcom_slv_outbox_rx[i].fwish == 0))
+ {
+ continue;
+ }
+ if (G_dcom_slv_outbox_rx[i].fwish > l_highest_fwish)
+ {
+ l_highest_fwish = G_dcom_slv_outbox_rx[i].fwish;
+ }
+ }
+
+ // If the highest Fwish is in range, go for it. Otherwise, step
+ // towards it in small steps
+ if ((l_highest_fwish >= G_mst_soft_fmin) &&
+ (l_highest_fwish <= G_mst_soft_fmax))
+ {
+ l_ftarget = l_highest_fwish;
+ }
+ else if (l_highest_fwish > G_mst_soft_fmax)
+ {
+ // Fwish is too high for range, step up (new target is the
+ // old soft Fmax)
+ l_ftarget = G_mst_soft_fmax;
+ }
+ else
+ {
+ // Fwish is too low for range, step down (new target is the
+ // old soft Fmin)
+ l_ftarget = G_mst_soft_fmin;
+ }
+ }
+ else
+ {
+ // For other system power modes, calculate the lowest Fwish sent
+ // by all slave OCCs
+ l_lowest_fwish = 0xFFFF;
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ // Ignore OCCs that are sending zeros for factual or fwish
+ if ((G_dcom_slv_outbox_rx[i].factual == 0) ||
+ (G_dcom_slv_outbox_rx[i].fwish == 0))
+ {
+ continue;
+ }
+ if ((G_dcom_slv_outbox_rx[i].fwish < l_lowest_fwish) &&
+ (G_dcom_slv_outbox_rx[i].fwish != 0))
+ {
+ l_lowest_fwish = G_dcom_slv_outbox_rx[i].fwish;
+ }
+ }
+
+ // If the lowest Fwish is in range, go for it. Otherwise, step
+ // towards it in small steps
+ if ((l_lowest_fwish >= G_mst_soft_fmin) &&
+ (l_lowest_fwish <= G_mst_soft_fmax))
+ {
+ l_ftarget = l_lowest_fwish;
+ }
+ else if (l_lowest_fwish > G_mst_soft_fmax)
+ {
+ // Fwish is too high for range, step up (new target is the
+ // old soft Fmax)
+ l_ftarget = G_mst_soft_fmax;
+ }
+ else
+ {
+ // Fwish is too low for range, step down (new target is the
+ // old soft Fmin)
+ l_ftarget = G_mst_soft_fmin;
+ }
+ }
+ }
+
+ // Calculate the new soft frequency boundaries
+ G_mst_soft_fmin = l_ftarget - l_fdelta;
+ G_mst_soft_fmax = l_ftarget + l_fdelta;
+
+ } while(0);
+}
+
+
+// Function Specification
+//
+// Name: amec_mst_cmmon_tasks_pre
+//
+// Description: master common tasks pre function
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_mst_common_tasks_pre(void)
+{
+ AMEC_DBG("\tAMEC Master Pre-State Common\n");
+
+ // ------------------------------------------------------
+ //
+ // ------------------------------------------------------
+
+
+ // ------------------------------------------------------
+ //
+ // ------------------------------------------------------
+}
+
+
+// Function Specification
+//
+// Name: amec_mst_cmmon_tasks_post
+//
+// Description: master common tasks post function
+//
+// End Function Specification
+void amec_mst_common_tasks_post(void)
+{
+ AMEC_DBG("\tAMEC Master Post-State Common\n");
+
+ // Only execute if OCC is in the active state
+ if ( IS_OCC_STATE_ACTIVE() )
+ {
+ // Call the OCC auto-slew function
+ amec_master_auto_slew();
+
+ //Call OCC pcaps mismatch function
+ amec_mst_check_pcaps_match();
+
+ //Call check under power cap function
+ amec_mst_check_under_pcap();
+ }
+}
+
+
+// Function Specification
+//
+// Name: amec_mst_state_0 ~ amec_mst_state_7
+//
+// Description: master state 0 ~ 7 functions
+//
+// End Function Specification
+void amec_mst_state_0(void){AMEC_DBG("\tAMEC Master State 0\n");}
+void amec_mst_state_1(void){AMEC_DBG("\tAMEC Master State 1\n");}
+void amec_mst_state_2(void){AMEC_DBG("\tAMEC Master State 2\n");}
+void amec_mst_state_3(void){AMEC_DBG("\tAMEC Master State 3\n");}
+void amec_mst_state_4(void){AMEC_DBG("\tAMEC Master State 4\n");}
+
+void amec_mst_state_5(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ static uint16_t l_counter = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ AMEC_DBG("\tAMEC Master State 5\n");
+
+ // Only execute if OCC is in the active state
+ if ( IS_OCC_STATE_ACTIVE() )
+ {
+ // Increment our local counter
+ l_counter++;
+
+ // Is it time to run the Idle Power Saver algorithm? (default is 3sec)
+ if (l_counter == AMEC_DPS_SAMPLING_RATE * AMEC_IPS_AVRG_INTERVAL)
+ {
+ l_counter = 0;
+ amec_mst_ips_main();
+ }
+ }
+}
+
+void amec_mst_state_6(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ AMEC_DBG("\tAMEC Master State 6\n");
+
+ if ( IS_OCC_STATE_ACTIVE() )
+ {
+ amec_mst_gen_soft_freq();
+ }
+}
+
+void amec_mst_state_7(void){AMEC_DBG("\tAMEC Master State 7\n");}
+
+// Function Specification
+//
+// Name: amec_mst_substate_0_0
+// amec_mst_substate_0_1
+//
+// Description: master substate amec_mst_substate_0_0
+// master substate amec_mst_substate_0_1
+//
+// End Function Specification
+void amec_mst_substate_0_0(void){AMEC_DBG("\tAMEC Master SubState 0.0\n");}
+void amec_mst_substate_0_1(void){AMEC_DBG("\tAMEC Master SubState 0.1\n");}
+
+// Function Specification
+//
+// Name: amec_mst_substate_6_0
+// amec_mst_substate_6_1
+// amec_mst_substate_6_2
+// amec_mst_substate_6_3
+// amec_mst_substate_6_4
+// amec_mst_substate_6_5
+// amec_mst_substate_6_6
+// amec_mst_substate_6_7
+//
+// Description: master substate amec_mst_substate_6_0
+// master substate amec_mst_substate_6_1
+// master substate amec_mst_substate_6_2
+// master substate amec_mst_substate_6_3
+// master substate amec_mst_substate_6_4
+// master substate amec_mst_substate_6_5
+// master substate amec_mst_substate_6_6
+// master substate amec_mst_substate_6_7
+//
+// Flow: FN= None
+//
+// End Function Specification
+void amec_mst_substate_6_0(void){AMEC_DBG("\tAMEC Master State 6.0\n");}
+void amec_mst_substate_6_1(void){AMEC_DBG("\tAMEC Master State 6.1\n");}
+void amec_mst_substate_6_2(void){AMEC_DBG("\tAMEC Master State 6.2\n");}
+void amec_mst_substate_6_3(void){AMEC_DBG("\tAMEC Master State 6.3\n");}
+void amec_mst_substate_6_4(void){AMEC_DBG("\tAMEC Master State 6.4\n");}
+void amec_mst_substate_6_5(void){AMEC_DBG("\tAMEC Master State 6.5\n");}
+void amec_mst_substate_6_6(void){AMEC_DBG("\tAMEC Master State 6.6\n");}
+void amec_mst_substate_6_7(void){AMEC_DBG("\tAMEC Master State 6.7\n");}
+
+// Function Specification
+//
+// Name: amec_mst_substate_3_0
+// amec_mst_substate_3_1
+//
+// Description: master substate amec_mst_substate_3_0
+// master substate amec_mst_substate_3_1
+//
+// Flow: FN= None
+//
+// End Function Specification
+void amec_mst_substate_3_0(void){AMEC_DBG("\tAMEC Master State 3.0\n");}
+void amec_mst_substate_3_1(void){AMEC_DBG("\tAMEC Master State 3.1\n");}
+
+
+// Function Specification
+//
+// Name: amec_mst_substate_6_1_0
+// amec_mst_substate_6_1_1
+// amec_mst_substate_6_1_2
+// amec_mst_substate_6_1_3
+// amec_mst_substate_6_1_4
+// amec_mst_substate_6_1_5
+// amec_mst_substate_6_1_6
+// amec_mst_substate_6_1_7
+//
+// Description: master substate amec_mst_substate_6_1_0
+// master substate amec_mst_substate_6_1_1
+// master substate amec_mst_substate_6_1_2
+// master substate amec_mst_substate_6_1_3
+// master substate amec_mst_substate_6_1_4
+// master substate amec_mst_substate_6_1_5
+// master substate amec_mst_substate_6_1_6
+// master substate amec_mst_substate_6_1_7
+//
+// Flow: FN= None
+//
+// End Function Specification
+void amec_mst_sub_substate_6_1_0(void){AMEC_DBG("\tAMEC Master State 6.1.0\n");}
+void amec_mst_sub_substate_6_1_1(void){AMEC_DBG("\tAMEC Master State 6.1.1\n");}
+void amec_mst_sub_substate_6_1_2(void){AMEC_DBG("\tAMEC Master State 6.1.2\n");}
+void amec_mst_sub_substate_6_1_3(void){AMEC_DBG("\tAMEC Master State 6.1.3\n");}
+void amec_mst_sub_substate_6_1_4(void){AMEC_DBG("\tAMEC Master State 6.1.4\n");}
+void amec_mst_sub_substate_6_1_5(void){AMEC_DBG("\tAMEC Master State 6.1.5\n");}
+void amec_mst_sub_substate_6_1_6(void){AMEC_DBG("\tAMEC Master State 6.1.6\n");}
+void amec_mst_sub_substate_6_1_7(void){AMEC_DBG("\tAMEC Master State 6.1.7\n");}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_master_smh.h b/src/occ_405/amec/amec_master_smh.h
new file mode 100755
index 0000000..59563f6
--- /dev/null
+++ b/src/occ_405/amec/amec_master_smh.h
@@ -0,0 +1,162 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_master_smh.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 _AMEC_MASTER_SMH_H
+#define _AMEC_MASTER_SMH_H
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include <ssx_app_cfg.h>
+#include <amec_smh.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+#define AMEC_MST_STATE() AMEC_STATE(&G_amec_mst_state);
+#define AMEC_MST_SUBSTATE() AMEC_SUBSTATE(&G_amec_mst_state);
+#define AMEC_MST_SUB_SUBSTATE() AMEC_SUB_SUBSTATE(&G_amec_mst_state);
+
+#define AMEC_MST_STATE_NEXT() AMEC_STATE_NEXT(&G_amec_mst_state);
+#define AMEC_MST_SUBSTATE_NEXT() AMEC_SUBSTATE_NEXT(&G_amec_mst_state);
+#define AMEC_MST_SUB_SUBSTATE_NEXT() AMEC_SUB_SUBSTATE_NEXT(&G_amec_mst_state);
+
+#define AMEC_MST_SET_MNFG_FMIN(a) AMEC_MST_CUR_MNFG_FMIN() = a
+#define AMEC_MST_SET_MNFG_FMAX(a) AMEC_MST_CUR_MNFG_FMAX() = a
+#define AMEC_MST_SET_MNFG_FSTEP(a) g_amec->mnfg_parms.fstep = a
+#define AMEC_MST_SET_MNFG_DELAY(a) g_amec->mnfg_parms.delay = a
+#define AMEC_MST_START_AUTO_SLEW() g_amec->mnfg_parms.auto_slew = 1
+#define AMEC_MST_STOP_AUTO_SLEW() g_amec->mnfg_parms.auto_slew = 0
+#define AMEC_MST_CUR_SLEW_COUNT() g_amec->mnfg_parms.slew_counter
+#define AMEC_MST_CUR_MNFG_FMIN() g_amec->mnfg_parms.fmin
+#define AMEC_MST_CUR_MNFG_FMAX() g_amec->mnfg_parms.fmax
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+extern const smh_tbl_t amec_mst_state_table[AMEC_SMH_STATES_PER_LVL];
+extern smh_state_t G_amec_mst_state;
+extern smh_state_timing_t G_amec_mst_state_timings;
+
+typedef struct
+{
+ uint16_t active_pcap;
+ uint8_t pcap_valid;
+ uint8_t reserved;
+}slave_pcap_info_t;
+
+extern slave_pcap_info_t G_slave_active_pcaps[MAX_OCCS];
+extern uint8_t G_pcaps_mismatch_count;
+extern uint8_t G_over_cap_count;
+extern uint16_t G_mst_soft_fmin;
+extern uint16_t G_mst_soft_fmax;
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+void amec_mst_update_smh_sensors(int i_smh_state, uint32_t i_duration);
+
+// PRE: master common tasks
+void amec_mst_common_tasks_pre(void);
+// POST: master common tasks
+void amec_mst_common_tasks_post(void);
+
+// Master auto-slewing function
+void amec_master_auto_slew(void);
+// OCC Power cap mismatch function
+void amec_mst_check_pcaps_match(void);
+// Check if under power cap function
+void amex_mst_check_under_pcap(void);
+// Idle Power Saver main algorithm
+void amec_mst_ips_main(void);
+// Get the current Idle Power Saver active status
+uint8_t AMEC_mst_get_ips_active_status();
+void amec_mst_gen_soft_freq(void);
+
+// Master States
+void amec_mst_state_0(void);
+void amec_mst_state_1(void);
+void amec_mst_state_2(void);
+void amec_mst_state_3(void);
+void amec_mst_state_4(void);
+void amec_mst_state_5(void);
+void amec_mst_state_6(void);
+void amec_mst_state_7(void);
+
+// Master SubState 0
+void amec_mst_substate_0_0(void);
+void amec_mst_substate_0_1(void);
+void amec_mst_substate_0_4(void);
+void amec_mst_substate_0_7(void);
+
+// Master SubState 3
+void amec_mst_substate_3_0(void);
+void amec_mst_substate_3_1(void);
+void amec_mst_substate_3_2(void);
+void amec_mst_substate_3_6(void);
+void amec_mst_substate_3_7(void);
+
+// Master Sub-SubState 3
+void amec_mst_sub_substate_3_0_0(void);
+void amec_mst_sub_substate_3_0_1(void);
+void amec_mst_sub_substate_3_0_7(void);
+
+// Master SubState 6
+void amec_mst_substate_6_0(void);
+void amec_mst_substate_6_1(void);
+void amec_mst_substate_6_2(void);
+void amec_mst_substate_6_3(void);
+void amec_mst_substate_6_4(void);
+void amec_mst_substate_6_5(void);
+void amec_mst_substate_6_6(void);
+void amec_mst_substate_6_7(void);
+
+void amec_mst_substate_3_0(void);
+void amec_mst_substate_3_1(void);
+
+void amec_mst_sub_substate_6_1_0(void);
+void amec_mst_sub_substate_6_1_1(void);
+void amec_mst_sub_substate_6_1_2(void);
+void amec_mst_sub_substate_6_1_3(void);
+void amec_mst_sub_substate_6_1_4(void);
+void amec_mst_sub_substate_6_1_5(void);
+void amec_mst_sub_substate_6_1_6(void);
+void amec_mst_sub_substate_6_1_7(void);
+
+#endif
diff --git a/src/occ_405/amec/amec_oversub.c b/src/occ_405/amec/amec_oversub.c
new file mode 100755
index 0000000..beff792
--- /dev/null
+++ b/src/occ_405/amec/amec_oversub.c
@@ -0,0 +1,252 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_oversub.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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include "ssx.h"
+#include <occ_common.h>
+#include <trac.h>
+#include <amec_sys.h>
+#include <proc_pstate.h>
+#include <dcom.h>
+#include <occ_sys_config.h>
+#include <amec_service_codes.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+#define OVERSUB_REASON_DELAY_4MS 16 // 4ms (unit is 250us)
+#define OVERSUB_REASON_COUNT_TIMEOUT 2
+#define OVERSUB_REASON_DETERMINED 1
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// Function Specification
+//
+// Name: amec_oversub_pmax_clip
+//
+// Description: Set Pmax_Clip in PMC to lowest Pstate
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_oversub_pmax_clip(Pstate i_pstate)
+{
+ pmc_rail_bounds_register_t prbr;
+
+ // Set Pmax_Clip in PMC to lowest Pstate
+ prbr.value = in32(PMC_RAIL_BOUNDS_REGISTER);
+ prbr.fields.pmax_rail = i_pstate;
+ out32(PMC_RAIL_BOUNDS_REGISTER, prbr.value);
+}
+
+// Function Specification
+//
+// Name: amec_oversub_isr
+//
+// Description: Oversubscription ISR
+//
+// Task Flags:
+//
+// Note: This function is only ever called from Critical interrupt context
+//
+// End Function Specification
+void amec_oversub_isr(void)
+{
+ static uint32_t l_isr_count = 0;
+ static uint8_t l_polarity = SSX_IRQ_POLARITY_ACTIVE_LOW; // Default is low
+ uint8_t l_cur_polarity = l_polarity;
+
+ l_isr_count++;
+
+ // SSX_IRQ_POLARITY_ACTIVE_LOW means over-subscription is active
+ if(l_polarity == SSX_IRQ_POLARITY_ACTIVE_LOW)
+ {
+ // If RTL doesn't control it, do it here
+ if(g_amec->oversub_status.oversubLatchAmec == 0)
+ {
+ // Set PMC Pmax_clip to Pmin and throttle all Cores via OCI write to PMC
+ amec_oversub_pmax_clip(gpst_pmin(&G_global_pstate_table));
+
+ // TODO: Throttle all Centaurs via PORE-GPE by setting 'Emergency Throttle'
+
+ g_amec->oversub_status.oversubReasonLatchCount = OVERSUB_REASON_DELAY_4MS;
+ }
+
+ // Set oversubPinLive and oversubActiveTime
+ g_amec->oversub_status.oversubPinLive = 1;
+ g_amec->oversub_status.oversubActiveTime = ssx_timebase_get();
+
+ // Setup the IRQ
+ ssx_irq_setup(PGP_IRQ_EXTERNAL_TRAP,
+ SSX_IRQ_POLARITY_ACTIVE_HIGH,
+ SSX_IRQ_TRIGGER_LEVEL_SENSITIVE);
+ l_polarity = SSX_IRQ_POLARITY_ACTIVE_HIGH;
+
+ }
+ else // over-subscription is inactive
+ {
+ // Clear oversubPinLive
+ g_amec->oversub_status.oversubPinLive = 0;
+
+ // Set oversubInActiveTime
+ g_amec->oversub_status.oversubInactiveTime = ssx_timebase_get();
+
+ // Setup the IRQ
+ ssx_irq_setup(PGP_IRQ_EXTERNAL_TRAP,
+ SSX_IRQ_POLARITY_ACTIVE_LOW,
+ SSX_IRQ_TRIGGER_LEVEL_SENSITIVE);
+
+ l_polarity = SSX_IRQ_POLARITY_ACTIVE_LOW;
+ }
+
+ // Trace Oversub Event, Polarity and ISR count
+ TRAC_INFO("Oversub IRQ - Polarity (low active):%d, oversubPinLive: %d, count: %d)", l_cur_polarity, g_amec->oversub_status.oversubPinLive, l_isr_count);
+
+}
+
+// Function Specification
+//
+// Name: amec_oversub_check
+//
+// Description: Oversubscription check called in amec_slv_common_tasks_pre()
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_oversub_check(void)
+{
+ uint8_t l_cme_pin_value = 1; // low active, so set default to high
+ static BOOLEAN l_prev_ovs_state = FALSE; // oversub happened
+
+ // Get CME Pin state
+ // No longer reading gpio from APSS in GA1 due to instability in APSS composite mode
+ //apss_gpio_get(l_cme_pin, &l_cme_pin_value);
+
+ // Check CME Pin? OR CME Oversub Mnfg Active
+ if( (l_cme_pin_value == 0) ||
+ (g_amec->oversub_status.cmeThrottlePinMnfg == 1) )
+ {
+ g_amec->oversub_status.cmeThrottlePinLive = 1;
+ g_amec->oversub_status.cmeThrottleLatchAmec = 1;
+ }
+ else
+ {
+ // Do not clear cmeThrottleLatchAmec.
+ // That will only be done via the PowerCa command from TMGT.
+ g_amec->oversub_status.cmeThrottlePinLive = 0;
+ }
+
+ // oversubscription condition happened?
+ if ( AMEC_INTF_GET_OVERSUBSCRIPTION() == TRUE )
+ {
+ if ( l_prev_ovs_state != TRUE)
+ {
+ l_prev_ovs_state = TRUE;
+
+ TRAC_ERR("Oversubscription condition happened");
+ /* @
+ * @errortype
+ * @moduleid AMEC_SLAVE_CHECK_PERFORMANCE
+ * @reasoncode OVERSUB_ALERT
+ * @userdata1 Previous OVS State
+ * @userdata4 ERC_AMEC_SLAVE_OVS_STATE
+ * @devdesc Oversubscription condition happened
+ */
+ errlHndl_t l_errl = createErrl(AMEC_SLAVE_CHECK_PERFORMANCE,//modId
+ OVERSUB_ALERT, //reasoncode
+ ERC_AMEC_SLAVE_OVS_STATE, //Extended reason code
+ ERRL_SEV_INFORMATIONAL, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_prev_ovs_state, //userdata1
+ 0); //userdata2
+
+ // set the mfg action flag (allows callout to be added to info error)
+ setErrlActions(l_errl, ERRL_ACTIONS_MANUFACTURING_ERROR);
+
+ // add the oversubscription symbolic callout
+ addCalloutToErrl(l_errl,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_OVERSUBSCRIPTION,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ // Commit Error
+ commitErrl(&l_errl);
+ }
+ }
+ else
+ {
+ l_prev_ovs_state = FALSE;
+ }
+
+ // Figure out the over-subscription reason
+ if(g_amec->oversub_status.oversubReasonLatchCount > 1)
+ {
+ // Try to figure out why we throttled based on APSS GPIO pins
+ if( g_amec->oversub_status.oversubReasonLatchCount == OVERSUB_REASON_COUNT_TIMEOUT)
+ {
+ g_amec->oversub_status.oversubReason = INDETERMINATE;
+ g_amec->oversub_status.oversubReasonLatchCount = OVERSUB_REASON_DETERMINED;
+
+ TRAC_INFO("Oversub (oversubReason: %d)", g_amec->oversub_status.oversubReason );
+ }
+ else
+ {
+ // If we can figure out why oversub happened, set oversubReason to valide enum value
+ // then set oversubReasonLatchCount = 1
+
+ // If we can't figure it out, decrease oversubReasonLatchCount and we will try again in 250us
+ g_amec->oversub_status.oversubReasonLatchCount--; // The unit of oversubReasonLatchCount is 250us
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_oversub.h b/src/occ_405/amec/amec_oversub.h
new file mode 100755
index 0000000..238599a
--- /dev/null
+++ b/src/occ_405/amec/amec_oversub.h
@@ -0,0 +1,117 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_oversub.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 _AMEC_OVERSUB_H
+#define _AMEC_OVERSUB_H
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+#include <occ_sys_config.h> // Added for sys config access
+#include <dcom.h>
+
+/*----------------------------------------------------------------------------*/
+/* Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Globals */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Defines */
+/*----------------------------------------------------------------------------*/
+#define AMEC_INTF_GET_OVERSUBSCRIPTION() \
+(G_sysConfigData.failsafe_enabled ? g_amec->oversub_status.cmeThrottlePinLive : \
+ (g_amec->oversub_status.oversubPinLive || G_dcom_slv_inbox_rx.emulate_oversub))
+
+#define AMEC_INTF_GET_OVERSUBSCRIPTION_EMULATION() g_amec->oversub_status.oversubPinMnfg
+
+#define AMEC_INTF_GET_FAILSAFE() \
+(G_sysConfigData.failsafe_enabled ? g_amec->oversub_status.oversubPinLive : 0)
+
+/*----------------------------------------------------------------------------*/
+/* Typedef / Enum */
+/*----------------------------------------------------------------------------*/
+typedef enum oversub_reason
+{
+ PENDING_OR_INVALID = 0x00,
+ FANS_FULL_SPEED = 0x01,
+ FAN_ERRROR = 0x02,
+ FAN_WARNING = 0x03,
+ ITE_FAILSAFE = 0x04,
+
+ INDETERMINATE = 0xFF
+}oversub_reason_t;
+
+typedef struct oversub_status
+{
+ // Way to emulate oversub for MNFG or Developers
+ uint32_t oversubPinMnfg : 1;
+
+ // Live Status of oversub Pin
+ uint32_t oversubPinLive : 1;
+
+ // AMEC status of oversub pin, so it doesn't
+ // change mid-RTL
+ uint32_t oversubLatchAmec : 1;
+
+ // Used for SRC logging of performance loss,
+ // need to have countdown b/c we don't get
+ // APSS gpio signals as quick as we get
+ // oversub.
+ uint8_t oversubReasonLatchCount;
+ oversub_reason_t oversubReason;
+
+ // For debug, tracks time oversub last went inactive
+ SsxTimebase oversubInactiveTime;
+
+ // For debug, tracks time oversub last went active
+ SsxTimebase oversubActiveTime;
+
+ // Live status of CME throttle pin, doesn't change mid-RTL
+ uint32_t cmeThrottlePinLive :1;
+
+ // Status of CME Throttle, doesn't get cleared until MM/TMGT
+ // tells us to clear it/un-throttle.
+ uint32_t cmeThrottleLatchAmec :1;
+
+ // Way to emulate cmeThrottle for MNFG or Developers
+ uint32_t cmeThrottlePinMnfg :1;
+}oversub_status_t;
+
+/*----------------------------------------------------------------------------*/
+/* Function Prototypes */
+/*----------------------------------------------------------------------------*/
+
+void amec_oversub_isr(void);
+
+void amec_oversub_check(void);
+
+void amec_oversub_pmax_clip(Pstate i_pstate);
+
+bool apss_gpio_get(uint8_t i_pin_number, uint8_t *o_pin_value);
+
+#endif //_AMEC_OVERSUB_H
diff --git a/src/occ_405/amec/amec_parm.c b/src/occ_405/amec/amec_parm.c
new file mode 100755
index 0000000..a3dafd6
--- /dev/null
+++ b/src/occ_405/amec/amec_parm.c
@@ -0,0 +1,306 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_parm.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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <common_types.h>
+#include <amec_parm.h>
+#include <string.h>
+#include <stdlib.h>
+#include <occ_common.h>
+#include <amec_amester.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+///Array that maintains a list of all parameters built
+extern amec_parm_t g_amec_parm_list[];
+
+//*************************************************************************
+// Function Declarations
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+void amec_parm_get_number(const IPMIMsg_t *i_psMsg,
+ UINT8 *o_pu8Resp,
+ UINT16 *o_pu16RespLength,
+ UINT8 *o_retval)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ o_pu8Resp[0] = (UINT8)(AMEC_PARM_NUMBER_OF_PARAMETERS>>8);
+ o_pu8Resp[1] = (UINT8)(AMEC_PARM_NUMBER_OF_PARAMETERS);
+
+ *o_pu16RespLength=2;
+ *o_retval=COMPCODE_NORMAL;
+
+ return;
+}
+
+
+void amec_parm_get_config(const IPMIMsg_t *i_psMsg,
+ UINT8 *o_pu8Resp,
+ UINT16 *o_pu16RespLength,
+ UINT8 *o_retval)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ AMEC_PARM_GUID l_id; // parameter id
+ UINT16 l_j; // index into return message
+ UINT16 l_length = 0; // response length
+ CHAR *l_src; //pointer for copying name
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ l_id = (AMEC_PARM_GUID) CONVERT_UINT8_ARRAY_UINT16(
+ i_psMsg->au8CmdData_ptr[1],
+ i_psMsg->au8CmdData_ptr[2]);
+ l_j = 0; // write index byte for response
+
+ for (; l_id < AMEC_PARM_NUMBER_OF_PARAMETERS; l_id++)
+ {
+ if (l_j + strlen(g_amec_parm_list[l_id].name) + 1 + 10 >= IPMI_MAX_MSG_SIZE)
+ {
+ // +1 = null terminator in name.
+ // +10 = type, mode, vector_length, length (optional)
+ break; // hit end of response buffer
+ }
+
+ // Copy name into output buffer
+ l_src = g_amec_parm_list[l_id].name;
+ do
+ {
+ o_pu8Resp[l_j++] = *l_src;
+ } while (*l_src++ != 0); /* copy string until \0 */
+
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_parm_list[l_id].type);
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_parm_list[l_id].mode);
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_parm_list[l_id].vector_length>>24);
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_parm_list[l_id].vector_length>>16);
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_parm_list[l_id].vector_length>>8);
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_parm_list[l_id].vector_length);
+
+ // If base type is unstructured data or string, send length
+ if (g_amec_parm_list[l_id].type == AMEC_PARM_TYPE_STRING ||
+ g_amec_parm_list[l_id].type == AMEC_PARM_TYPE_RAW)
+ {
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_parm_list[l_id].length>>24);
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_parm_list[l_id].length>>16);
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_parm_list[l_id].length>>8);
+ o_pu8Resp[l_j++] = (UINT8)(g_amec_parm_list[l_id].length);
+ }
+
+ // update length of response parameter just copied
+ l_length = l_j;
+ }
+ *o_pu16RespLength=l_length;
+ *o_retval=COMPCODE_NORMAL;
+ return;
+}
+
+
+void amec_parm_read(const IPMIMsg_t *const i_psMsg,
+ UINT8 *const o_pu8Resp,
+ UINT16 *const o_pu16RespLength,
+ UINT8 *const o_retval)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ AMEC_PARM_GUID l_id;
+ UINT16 i=0; // output index
+ UINT16 l_maxresponse = IPMI_MAX_MSG_SIZE - 1; // -1 since return code is 1B
+ UINT8 *l_src_ptr; // pointer to first byte of data
+ UINT8 *l_end_ptr; // mark end of data
+ UINT32 b; // start byte
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ *o_retval = COMPCODE_NORMAL; /* assume no error */
+
+ // Parse input command
+ // Get the byte offset
+ b = CONVERT_UINT8_ARRAY_UINT32(
+ i_psMsg->au8CmdData_ptr[1],
+ i_psMsg->au8CmdData_ptr[2],
+ i_psMsg->au8CmdData_ptr[3],
+ i_psMsg->au8CmdData_ptr[4]);
+
+ // Get parameter id
+ l_id = CONVERT_UINT8_ARRAY_UINT16(
+ i_psMsg->au8CmdData_ptr[5],
+ i_psMsg->au8CmdData_ptr[6]);
+
+ if (l_id >= AMEC_PARM_NUMBER_OF_PARAMETERS)
+ {
+ *o_retval = COMPCODE_PARAM_OUT_OF_RANGE;
+ *o_pu16RespLength = 0;
+ break;
+ }
+
+ if (g_amec_parm_list[l_id].preread)
+ {
+ amec_parm_preread(l_id);
+ }
+
+ // Copy value to output buffer
+ // Set src to first byte to send back
+ l_src_ptr = g_amec_parm_list[l_id].value_ptr + b;
+
+ // Set end pointer 1 beyond last byte to send. It is limited either
+ // on the value size, or the IPMI message size.
+ l_end_ptr = g_amec_parm_list[l_id].value_ptr
+ + (g_amec_parm_list[l_id].vector_length * g_amec_parm_list[l_id].length);
+ if (l_src_ptr + l_maxresponse < l_end_ptr)
+ {
+ l_end_ptr = l_src_ptr + l_maxresponse;
+ }
+
+ while ((UINT32)l_src_ptr < (UINT32)l_end_ptr)
+ {
+ //Copy next byte to output
+ o_pu8Resp[i++] = (UINT8)*l_src_ptr++;
+ }
+
+ *o_pu16RespLength = i;
+
+ } while (FALSE);
+}
+
+
+void amec_parm_write(const IPMIMsg_t *const i_psMsg,
+ UINT8 *const o_pu8Resp,
+ UINT16 *const o_pu16RespLength,
+ UINT8 *const o_retval)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ AMEC_PARM_GUID l_id;
+ UINT16 i=0; // output index
+ UINT8 *l_dest_ptr = NULL; // pointer to first byte of data
+ UINT8 *l_start_ptr; // mark end of data
+ UINT8 *l_end_ptr = NULL; // mark end of data
+ UINT32 b; // start byte
+ UINT32 l_bytes = 0; // number of bytes written
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ *o_retval = COMPCODE_NORMAL; /* assume no error */
+
+ // Parse input command
+ // Get parameter id
+ l_id = CONVERT_UINT8_ARRAY_UINT16(
+ i_psMsg->au8CmdData_ptr[1],
+ i_psMsg->au8CmdData_ptr[2]);
+
+ // Get the starting byte of element
+ b = CONVERT_UINT8_ARRAY_UINT32(
+ i_psMsg->au8CmdData_ptr[3],
+ i_psMsg->au8CmdData_ptr[4],
+ i_psMsg->au8CmdData_ptr[5],
+ i_psMsg->au8CmdData_ptr[6]);
+
+ if (l_id >= AMEC_PARM_NUMBER_OF_PARAMETERS)
+ {
+ *o_retval = COMPCODE_PARAM_OUT_OF_RANGE;
+ *o_pu16RespLength = 0;
+ break;
+ }
+
+ i = 7; // start of data to write in input buffer
+
+ // Check if read-only
+ if (g_amec_parm_list[l_id].mode & AMEC_PARM_MODE_READONLY)
+ {
+ *o_retval = COMPCODE_WRONG_PRIV;
+ *o_pu16RespLength = 0;
+ break;
+ }
+
+ l_start_ptr = g_amec_parm_list[l_id].value_ptr + b;
+ l_dest_ptr = l_start_ptr;
+ // Set end pointer 1 beyond last byte to send. It is limited either
+ // on the value size, or the IPMI message size.
+ l_end_ptr = g_amec_parm_list[l_id].value_ptr
+ + (g_amec_parm_list[l_id].vector_length * g_amec_parm_list[l_id].length);
+
+ // Copy value from input buffer
+ while ((UINT32)l_dest_ptr < (UINT32)l_end_ptr
+ && i < i_psMsg->u8CmdDataLen)
+ {
+ *l_dest_ptr++ = i_psMsg->au8CmdData_ptr[i++];
+ }
+
+ l_bytes = l_dest_ptr - l_start_ptr;
+
+ // Return number of bytes written
+ *o_pu16RespLength = 4;
+ o_pu8Resp[0] = (UINT8)(l_bytes >> 24);
+ o_pu8Resp[1] = (UINT8)(l_bytes >> 16);
+ o_pu8Resp[2] = (UINT8)(l_bytes >> 8);
+ o_pu8Resp[3] = (UINT8)(l_bytes);
+
+ // Run post-write routine only if last byte of parameter was written
+ // Some long parameters require multiple write calls due to IPMI
+ // message limits, so we only call the postwrite routine when the
+ // last byte of the parameter is written.
+ if (l_dest_ptr == l_end_ptr && g_amec_parm_list[l_id].postwrite)
+ {
+ amec_parm_postwrite(l_id);
+ }
+
+ } while (FALSE);
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_parm.h b/src/occ_405/amec/amec_parm.h
new file mode 100755
index 0000000..83104f9
--- /dev/null
+++ b/src/occ_405/amec/amec_parm.h
@@ -0,0 +1,181 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_parm.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 */
+
+/*
+ This interface takes named memory objects (such as global variables)
+ and makes them accessible to Amester parameter for reading and
+ writing. Any memory location may become an Amester parameter.
+
+ To add a parameter,
+ 1. Add a new parameter id number in the AMEC_PARM_ENUM below.
+ 2. In the same position, add the parameter to g_amec_parm_list in
+ amec_parm_table.c
+ There are macros that help in adding a parameter to the table.
+ The macro typically takes a) the parameter id, b) a string name,
+ and c) a pointer to the memory location.
+*/
+
+#ifndef _AMEC_PARM_H
+#define _AMEC_PARM_H
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <amec_amester.h>
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+// List of all parameters
+// NOTE: The parameters must be in the same order as g_amec_parm_list[] in
+// amec_parm_table.c
+typedef enum
+{
+ PARM_SYS_FMAX,
+ PARM_SYS_FMIN,
+ PARM_GPST,
+ PARM_PSTATE_MHZ,
+ PARM_FREQ_REASON,
+ PARM_FREQ_OR,
+ PARM_FREQ_OR_EN,
+ PARM_SYS_THRM_SP,
+ PARM_SYS_THRM_GAIN,
+ PARM_SYS_THRM_RES,
+ PARM_SYS_THRM_SPEED,
+ PARM_SYS_THRM_FREQ,
+ PARM_SOFT_FMIN,
+ PARM_SOFT_FMAX,
+ PARM_TOD,
+ AMEC_PARM_NUMBER_OF_PARAMETERS
+} AMEC_PARM_ENUM;
+
+typedef enum
+{
+ AMEC_PARM_TYPE_UINT8 = 0,
+ AMEC_PARM_TYPE_UINT16,
+ AMEC_PARM_TYPE_UINT32,
+ AMEC_PARM_TYPE_UINT64,
+ AMEC_PARM_TYPE_INT8,
+ AMEC_PARM_TYPE_INT16,
+ AMEC_PARM_TYPE_INT32,
+ AMEC_PARM_TYPE_INT64,
+ AMEC_PARM_TYPE_STRING,
+ AMEC_PARM_TYPE_RAW
+
+} AMEC_PARM_TYPE_ENUM;
+
+#define AMEC_PARM_MODE_NORMAL (0x00)
+#define AMEC_PARM_MODE_READONLY (0x01)
+
+// Length includes null byte terminator. 15 readable characters are allowed.
+#define AMEC_PARM_NAME_LENGTH 16
+
+typedef struct amec_parm_s
+{
+ /// name of parameter
+ CHAR name[AMEC_PARM_NAME_LENGTH];
+ /// value_ptr: pointer to data
+ UINT8 *value_ptr;
+ /// number of bytes in base data
+ UINT32 length;
+ /// vector_length is the number of items in the array pointed by value ptr.
+ UINT32 vector_length;
+ /// Type of data
+ UINT8 type : 4;
+ /// Mode of data (read-write, read-only, etc.)
+ UINT8 mode : 1;
+ /// If preread is 1, call amec_parm_preread(GUID) before reading parameter value.
+ UINT8 preread : 1;
+ /// If postwrite is 1, call amec_parm_postwrite(GUID) before reading parameter value.
+ UINT8 postwrite : 1;
+} amec_parm_t;
+
+typedef UINT16 AMEC_PARM_GUID;
+
+extern amec_parm_t g_amec_parm_list[];
+
+/*******************************************************************/
+/* Function Definitions */
+/*******************************************************************/
+
+/**
+ * Get number of parameters tracked by OCC
+ *
+ */
+void amec_parm_get_number(const IPMIMsg_t *i_psMsg,
+ UINT8 *o_pu8Resp,
+ UINT16 *o_pu16RespLength,
+ UINT8 *o_retval);
+
+/**
+ * Get parameter configuration (names, types, size, etc.)
+ *
+ */
+void amec_parm_get_config(const IPMIMsg_t *i_psMsg,
+ UINT8 *o_pu8Resp,
+ UINT16 *o_pu16RespLength,
+ UINT8 *o_retval);
+
+/**
+ * Read a parameter value
+ *
+ */
+void amec_parm_read(const IPMIMsg_t *const i_psMsg,
+ UINT8 *const o_pu8Resp,
+ UINT16 *const o_pu16RespLength,
+ UINT8 *const o_retval);
+
+/**
+ * Write a value to a parameter
+ *
+ */
+void amec_parm_write(const IPMIMsg_t *const i_psMsg,
+ UINT8 *const o_pu8Resp,
+ UINT16 *const o_pu16RespLength,
+ UINT8 *const o_retval);
+
+/**
+ * Update parameter value before reading
+ *
+ * Some parameters need to be updated before reading.
+ * For example, a parameter that points to double-buffered
+ * that may be at a new memory location each time the
+ * parameter is examined.
+ * This routine only needs to be called when the parameter
+ * has a 'preread' field with a value of 1.
+ */
+void amec_parm_preread(AMEC_PARM_GUID i_parm_guid);
+
+/**
+ * Update parameter value after writing
+ *
+ * Some parameters trigger actions after writing.
+ * This routine only needs to be called when the parameter
+ * has been written and has a 'postwrite' field with a value of 1.
+ */
+void amec_parm_postwrite(AMEC_PARM_GUID i_parm_guid);
+
+#endif
diff --git a/src/occ_405/amec/amec_parm_table.c b/src/occ_405/amec/amec_parm_table.c
new file mode 100755
index 0000000..c485484
--- /dev/null
+++ b/src/occ_405/amec/amec_parm_table.c
@@ -0,0 +1,168 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_parm_table.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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h> //STATIC_ASSERT macro
+#include <amec_parm.h>
+#include <amec_sys.h>
+#include <proc_pstate.h> //global pstate table parameter
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+// Macros for parameters based on simple variables (read-write, not vectors)
+/**
+ * Create or update a parameter
+ *
+ * i_name: Name of parameter. If this name is the name of an existing
+ * parameter, then the existing parameter fields will be updated
+ * i_value: A pointer to the bytes representing the value of the parameter
+ * i_length: The length in bytes of the parameter value
+ * n: The number of elements if this parameter is a vector, otherwise = 1.
+ */
+#define AMEC_PARM_UINT8(i_num, i_name, i_value) \
+ [i_num] = {i_name,(void*)i_value,1,1,AMEC_PARM_TYPE_UINT8,0}
+#define AMEC_PARM_UINT16(i_num, i_name, i_value) \
+ [i_num] = {i_name,(void*)i_value,2,1,AMEC_PARM_TYPE_UINT16,0}
+#define AMEC_PARM_UINT32(i_num, i_name, i_value) \
+ [i_num] = {i_name,(void*)i_value,4,1,AMEC_PARM_TYPE_UINT32,0}
+#define AMEC_PARM_UINT64(i_num, i_name, i_value) \
+ [i_num] = {i_name,(void*)i_value,8,1,AMEC_PARM_TYPE_UINT64,0}
+#define AMEC_PARM_INT8(i_num, i_name, i_value) \
+ [i_num] = {i_name,(void*)i_value,1,1,AMEC_PARM_TYPE_INT8,0}
+#define AMEC_PARM_INT16(i_num, i_name, i_value) \
+ [i_num] = {i_name,(void*)i_value,2,1,AMEC_PARM_TYPE_INT16,0}
+#define AMEC_PARM_INT32(i_num, i_name, i_value) \
+ [i_num] = {i_name,(void*)i_value,4,1,AMEC_PARM_TYPE_INT32,0}
+#define AMEC_PARM_INT64(i_num, i_name, i_value) \
+ [i_num] = {i_name,(void*)i_value,8,1,AMEC_PARM_TYPE_IN64,0}
+#define AMEC_PARM_STRING(i_num, i_name, i_value, i_length) \
+ [i_num] = {i_name,(void*)i_value,i_length,1,AMEC_PARM_TYPE_STRING,0}
+#define AMEC_PARM_RAW(i_num, i_name, i_value, i_length) \
+ [i_num] = {i_name,(void*)i_value,i_length,1,AMEC_PARM_TYPE_RAW,0}
+
+//Use these macros when the parameter is an array of values.
+#define AMEC_PARM_UINT8_ARRAY(i_num, i_name, i_value, n) \
+ [i_num] = {i_name,(void*)i_value,1,n,AMEC_PARM_TYPE_UINT8,0}
+#define AMEC_PARM_UINT16_ARRAY(i_num, i_name, i_value, n) \
+ [i_num] = {i_name,(void*)i_value,2,n,AMEC_PARM_TYPE_UINT16,0}
+#define AMEC_PARM_UINT32_ARRAY(i_num, i_name, i_value, n) \
+ [i_num] = {i_name,(void*)i_value,4,n,AMEC_PARM_TYPE_UINT32,0}
+#define AMEC_PARM_UINT64_ARRAY(i_num, i_name, i_value, n) \
+ [i_num] = {i_name,(void*)i_value,8,n,AMEC_PARM_TYPE_UINT64,0}
+#define AMEC_PARM_INT8_ARRAY(i_num, i_name, i_value, n) \
+ [i_num] = {i_name,(void*)i_value,1,n,AMEC_PARM_TYPE_INT8,0}
+#define AMEC_PARM_INT16_ARRAY(i_num, i_name, i_value, n) \
+ [i_num] = {i_name,(void*)i_value,2,n,AMEC_PARM_TYPE_INT16,0}
+#define AMEC_PARM_INT32_ARRAY(i_num, i_name, i_value, n) \
+ [i_num] = {i_name,(void*)i_value,4,n,AMEC_PARM_TYPE_INT32,0}
+#define AMEC_PARM_INT64_ARRAY(i_num, i_name, i_value, n) \
+ [i_num] = {i_name,(void*)i_value,8,n,AMEC_PARM_TYPE_IN64,0}
+#define AMEC_PARM_STRING_ARRAY(i_num, i_name, i_value, i_length, n) \
+ [i_num] = {i_name,(void*)i_value,i_length,n,AMEC_PARM_TYPE_STRING,0}
+#define AMEC_PARM_RAW_ARRAY(i_num, i_name, i_value, i_length, n) \
+ [i_num] = {i_name,(void*)i_value,i_length,n,AMEC_PARM_TYPE_RAW,0}
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+extern amec_sys_t g_amec_sys;
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+// This is the list of all parameters seen by Amester
+//
+// Note: The parameters must be in the same order as in AMEC_PARM_ENUM
+// in amec_parm.h
+//
+// Future optimization: This table could be placed in main memory, not
+// the SRAM tank, since slow access to it is OK.
+amec_parm_t g_amec_parm_list[] = {
+ // System fmin and fmax
+ AMEC_PARM_UINT16(PARM_SYS_FMAX,"sys_fmax",&g_amec_sys.sys.fmax),
+ AMEC_PARM_UINT16(PARM_SYS_FMIN,"sys_fmin",&g_amec_sys.sys.fmin),
+
+ // Global Pstate table
+ AMEC_PARM_RAW(PARM_GPST,"gpst",&G_global_pstate_table,sizeof(GlobalPstateTable)),
+ // MHz per pstate
+ AMEC_PARM_UINT32(PARM_PSTATE_MHZ,"pstate_mhz",&G_mhz_per_pstate),
+ // frequency reason code per-core
+ AMEC_PARM_UINT32_ARRAY(PARM_FREQ_REASON,"freq_reason",g_amec_sys.proc[0].parm_f_reason,MAX_NUM_CORES),
+ // frequency override speed in MHz per-core
+ AMEC_PARM_UINT16_ARRAY(PARM_FREQ_OR,"freq_or",g_amec_sys.proc[0].parm_f_override,MAX_NUM_CORES),
+ // frequency override enable bit (1=active)
+ AMEC_PARM_UINT8(PARM_FREQ_OR_EN,"freq_or_en",&g_amec_sys.proc[0].parm_f_override_enable),
+
+ // Thermal controller parameters
+ AMEC_PARM_UINT16(PARM_SYS_THRM_SP,"sys_thrm_sp",&g_amec_sys.thermalproc.setpoint),
+ AMEC_PARM_UINT16(PARM_SYS_THRM_GAIN,"sys_thrm_gain",&g_amec_sys.thermalproc.Pgain),
+ AMEC_PARM_UINT16(PARM_SYS_THRM_RES,"sys_thrm_res",&g_amec_sys.thermalproc.total_res),
+ AMEC_PARM_UINT16(PARM_SYS_THRM_SPEED,"sys_thrm_speed",&g_amec_sys.thermalproc.speed_request),
+ AMEC_PARM_UINT16(PARM_SYS_THRM_FREQ,"sys_thrm_freq",&g_amec_sys.thermalproc.freq_request),
+
+ // Partition related parameters
+ AMEC_PARM_UINT16(PARM_SOFT_FMIN,"part_soft_fmin",&g_amec_sys.part_config.part_list[0].soft_fmin),
+ AMEC_PARM_UINT16(PARM_SOFT_FMAX,"part_soft_fmax",&g_amec_sys.part_config.part_list[0].soft_fmax),
+ AMEC_PARM_RAW(PARM_TOD,"apss_tod",&G_dcom_slv_inbox_doorbell_rx.tod,8),
+};
+
+//Throw a compiler error when the enum and array are not both updated
+STATIC_ASSERT((AMEC_PARM_NUMBER_OF_PARAMETERS != (sizeof(g_amec_parm_list)/sizeof(amec_parm_t))));
+
+void amec_parm_preread(AMEC_PARM_GUID i_parm_guid)
+{
+ switch (i_parm_guid)
+ {
+ default:
+ break;
+ }
+}
+
+void amec_parm_postwrite(AMEC_PARM_GUID i_parm_guid)
+{
+ switch (i_parm_guid)
+ {
+ default:
+ break;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_part.c b/src/occ_405/amec/amec_part.c
new file mode 100755
index 0000000..86f1b7e
--- /dev/null
+++ b/src/occ_405/amec/amec_part.c
@@ -0,0 +1,468 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_part.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 */
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+#include <common_types.h>
+#include <mode.h>
+#include <amec_sys.h>
+#include <amec_part.h>
+#include <trac.h>
+#include <dcom.h>
+
+/*----------------------------------------------------------------------------*/
+/* Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Globals */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Typedef / Enum */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Code */
+/*----------------------------------------------------------------------------*/
+
+// Given partition id, return pointer to existing partition or NULL
+static amec_part_t* amec_part_find_by_id(amec_part_config_t* i_config,
+ const uint8_t i_id)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ amec_part_t *l_part = NULL;
+ uint16_t l_idx = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ for (l_idx=0; l_idx<AMEC_PART_MAX_PART; l_idx++)
+ {
+ if (i_config->part_list[l_idx].id == i_id && i_config->part_list[l_idx].valid)
+ {
+ l_part = &(i_config->part_list[l_idx]);
+ break;
+ }
+ }
+
+ return l_part;
+}
+
+// Function Specification
+//
+// Name: amec_isr_speed_to_freq
+//
+// Description: Given a core, return a valid partition that owns it, or NULL.
+//
+// End Function Specification
+amec_part_t* amec_part_find_by_core(amec_part_config_t* i_config,
+ const uint16_t i_core_index)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ amec_part_t *l_part = NULL;
+ uint16_t l_part_index = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ if (i_core_index >= MAX_NUM_CORES)
+ {
+ break; // illegal core number
+ }
+ l_part_index = i_config->core2part[i_core_index];
+ if (l_part_index >= AMEC_PART_MAX_PART)
+ {
+ break; // illegal partition number
+ }
+ if (i_config->part_list[l_part_index].valid)
+ {
+ l_part = (amec_part_t*) &(i_config->part_list[l_part_index]);
+ }
+ } while(0);
+
+ return l_part;
+}
+
+// Function Specification
+//
+// Name: amec_part_add
+//
+// Description: Add a core group.
+//
+// End Function Specification
+void amec_part_add(uint8_t i_id)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ amec_part_t *l_part;
+ uint16_t l_idx = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ l_part = (amec_part_t*) amec_part_find_by_id(&g_amec->part_config,
+ i_id);
+ if (l_part != NULL)
+ {
+ break; // Partition already exists
+ }
+
+ // Find new slot
+ for (l_idx=0; l_idx<AMEC_PART_MAX_PART; l_idx++)
+ {
+ if (!g_amec->part_config.part_list[l_idx].valid)
+ {
+ l_part = &g_amec->part_config.part_list[l_idx];
+ break;
+ }
+ }
+
+ if (l_part == NULL)
+ {
+ // This should never happen, since table should be large enough
+ // to hold as many partitions as can be created on system.
+ break;
+ }
+
+ // Enter new partition into table with default values
+ l_part->id = i_id;
+ l_part->valid = 1; //Mark them as valid
+ l_part->ncores = 0; //No cores
+ for (l_idx=0; l_idx<AMEC_PART_NUM_CORES; l_idx++)
+ {
+ l_part->core_list[l_idx] = AMEC_PART_NUM_CORES;
+ }
+
+ // For now, create a single partition with all cores assigned to it
+ // until we write the interface to talk to PHYP
+ if (i_id == 0)
+ {
+ l_part->ncores = MAX_NUM_CORES;
+ for (l_idx=0; l_idx<MAX_NUM_CORES; l_idx++)
+ {
+ l_part->core_list[l_idx] = l_idx;
+ }
+ }
+
+ // Set default soft frequency boundaries to use full frequency range
+ l_part->soft_fmin = 0x0000;
+ l_part->soft_fmax = 0xFFFF;
+
+ // Set default values for DPS parameters (Favor Energy)
+ l_part->dpsalg.step_up = 8;
+ l_part->dpsalg.step_down = 8;
+ l_part->dpsalg.tlutil = 9800;
+ l_part->dpsalg.sample_count_util = 16;
+ l_part->dpsalg.epsilon_perc = 1800;
+ l_part->dpsalg.alpha_up = 9800;
+ l_part->dpsalg.alpha_down = 9800;
+ l_part->dpsalg.type = 0; //No algorithm is selected yet
+ l_part->dpsalg.freq_request = UINT16_MAX;
+
+ l_part->es_policy = OCC_INTERNAL_MODE_MAX_NUM;
+ l_part->follow_sysmode = TRUE;
+ }
+ while (0);
+
+ return;
+}
+
+void amec_part_init()
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_idx = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ // Initial core to partition mapping. Cores point to an invalid core group
+ // id.
+ // For now, we assume a single partition (id 0) with all cores assigned to
+ // it. Once the PHYP interface has been written, we can remove this
+ // assumption.
+ for (l_idx=0; l_idx<MAX_NUM_CORES; l_idx++)
+ {
+ g_amec->part_config.core2part[l_idx] = 0; // AMEC_PART_INVALID_ID;
+ }
+
+ for (l_idx=0; l_idx<AMEC_PART_MAX_PART; l_idx++)
+ {
+ // Creating all possible partitions
+ amec_part_add(l_idx);
+
+ g_amec->part_config.part_list[l_idx].dpsalg.util_speed_request = g_amec->sys.fmax;
+ }
+}
+
+void amec_part_update_dps_parameters(amec_part_t* io_part)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // If partition doesn't exist, just exit
+ if (io_part == NULL)
+ {
+ return;
+ }
+
+ // Check to see if parameter values have been overwritten by user
+ if (g_amec->slv_dps_param_overwrite == TRUE)
+ {
+ // Then, exit right away
+ return;
+ }
+
+ // By default, let's use the DPS-Favor Energy settings
+ io_part->dpsalg.step_up = 8;
+ io_part->dpsalg.step_down = 8;
+ io_part->dpsalg.tlutil = 9800;
+ io_part->dpsalg.sample_count_util = 16;
+ io_part->dpsalg.epsilon_perc = 1800;
+ io_part->dpsalg.alpha_up = 9800;
+ io_part->dpsalg.alpha_down = 9800;
+ io_part->dpsalg.type = 41;
+
+ // If core group policy is DPS-Favor Performance, then write those settings
+ if (io_part->es_policy == OCC_INTERNAL_MODE_DPS_MP)
+ {
+ io_part->dpsalg.step_up = 1000;
+ io_part->dpsalg.step_down = 8;
+ io_part->dpsalg.tlutil = 1000;
+ io_part->dpsalg.sample_count_util = 1;
+ io_part->dpsalg.epsilon_perc = 0;
+ io_part->dpsalg.alpha_up = 9990;
+ io_part->dpsalg.alpha_down = 9990;
+ io_part->dpsalg.type = 41;
+
+ // Check if this is a multi-node system
+ if (G_sysConfigData.system_type.single == 0)
+ {
+ // These parameter values will result in static turbo frequency
+ io_part->dpsalg.alpha_down = 0;
+ io_part->dpsalg.tlutil = 0;
+
+ TRAC_IMP("Multi-node system found! Updating DPS-FP parameters: single_node_bit[%u] alpha_down[%u] tlutil[%u]",
+ G_sysConfigData.system_type.single,
+ io_part->dpsalg.alpha_down,
+ io_part->dpsalg.tlutil);
+ }
+ }
+}
+
+void amec_part_update_perf_settings(amec_part_t* io_part)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t j = 0;
+ uint16_t l_core_index = 0;
+ amec_core_perf_counter_t* l_perf;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // If partition doesn't exist, just exit
+ if (io_part == NULL)
+ {
+ return;
+ }
+
+ switch (io_part->es_policy)
+ {
+ case OCC_INTERNAL_MODE_DPS:
+ case OCC_INTERNAL_MODE_DPS_MP:
+ // These policies require that we reset the internal performance
+ // settings of the cores in the partition
+ for (j=0; j<io_part->ncores; j++)
+ {
+ l_core_index = io_part->core_list[j];
+ l_perf = &g_amec->proc[0].core[l_core_index % MAX_NUM_CORES].core_perf;
+
+ memset(l_perf->ptr_util_slack_avg_buffer, 0, 2*MAX_UTIL_SLACK_AVG_LEN);
+ memset(l_perf->ptr_util_active_avg_buffer, 0, 2*MAX_UTIL_SLACK_AVG_LEN);
+ l_perf->util_active_core_counter = 0;
+ l_perf->util_slack_core_counter = 0;
+ l_perf->util_slack_accumulator = 0;
+ l_perf->util_active_accumulator = 0;
+ l_perf->ptr_putUtilslack = 0;
+ }
+ break;
+
+ default:
+ // For all other policies, reset the DPS frequency request
+ for (j=0; j<io_part->ncores; j++)
+ {
+ l_core_index = io_part->core_list[j];
+ g_amec->proc[0].core[l_core_index % MAX_NUM_CORES]
+ .core_perf.dps_freq_request = UINT16_MAX;
+ }
+ break;
+ }
+}
+
+void AMEC_part_update_sysmode_policy(OCC_MODE i_occ_internal_mode)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t i = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ for (i=0; i<AMEC_PART_MAX_PART; i++)
+ {
+ // If a core group is not valid, skip it
+ if (!g_amec->part_config.part_list[i].valid)
+ {
+ continue;
+ }
+ // If a core group has no cores assigned, skip it
+ if (g_amec->part_config.part_list[i].ncores == 0)
+ {
+ continue;
+ }
+
+ // If a core group is not following the system power mode, skip it
+ if (!g_amec->part_config.part_list[i].follow_sysmode)
+ {
+ continue;
+ }
+
+ // Set power mode for this core group to the system power mode
+ switch (i_occ_internal_mode)
+ {
+ case OCC_MODE_NOMINAL:
+ g_amec->part_config.part_list[i].es_policy = OCC_INTERNAL_MODE_NOM;
+ break;
+
+ case OCC_MODE_DYN_POWER_SAVE:
+ g_amec->part_config.part_list[i].es_policy = OCC_INTERNAL_MODE_DPS;
+ break;
+
+ case OCC_MODE_DYN_POWER_SAVE_FP:
+ g_amec->part_config.part_list[i].es_policy = OCC_INTERNAL_MODE_DPS_MP;
+ break;
+
+ default:
+ g_amec->part_config.part_list[i].es_policy = OCC_INTERNAL_MODE_UNDEFINED;
+ break;
+ }
+
+ // Update the DPS parameters based on the power policy
+ if ((g_amec->part_config.part_list[i].es_policy == OCC_INTERNAL_MODE_DPS) ||
+ (g_amec->part_config.part_list[i].es_policy == OCC_INTERNAL_MODE_DPS_MP))
+ {
+ amec_part_update_dps_parameters(&(g_amec->part_config.part_list[i]));
+ }
+
+ // Update internal performance settings for this partition
+ amec_part_update_perf_settings(&(g_amec->part_config.part_list[i]));
+
+ // Useful trace for debug
+ //TRAC_INFO("AMEC_part_update_sysmode_policy: Core_group[%u] Num_cores[%u] ES_policy[0x%02x]",
+ // i, g_amec->part_config.part_list[i].ncores,
+ // g_amec->part_config.part_list[i].es_policy);
+ }
+}
+
+void AMEC_part_overwrite_dps_parameters(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t i = 0;
+ uint16_t j = 0;
+ uint16_t l_core_index = 0;
+ amec_part_t* l_part = NULL;
+ amec_core_perf_counter_t* l_perf = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ for (i=0; i<AMEC_PART_MAX_PART; i++)
+ {
+ // If a core group is not valid, skip it
+ if (!g_amec->part_config.part_list[i].valid)
+ {
+ continue;
+ }
+ // If a core group has no cores assigned, skip it
+ if (g_amec->part_config.part_list[i].ncores == 0)
+ {
+ continue;
+ }
+
+ // Overwrite the DPS parameters based on values sent by Master OCC
+ l_part = &(g_amec->part_config.part_list[i]);
+ l_part->dpsalg.alpha_up = G_dcom_slv_inbox_rx.alpha_up;
+ l_part->dpsalg.alpha_down = G_dcom_slv_inbox_rx.alpha_down;
+ l_part->dpsalg.sample_count_util = G_dcom_slv_inbox_rx.sample_count_util;
+ l_part->dpsalg.step_up = G_dcom_slv_inbox_rx.step_up;
+ l_part->dpsalg.step_down = G_dcom_slv_inbox_rx.step_down;
+ l_part->dpsalg.epsilon_perc = G_dcom_slv_inbox_rx.epsilon_perc;
+ l_part->dpsalg.tlutil = G_dcom_slv_inbox_rx.tlutil;
+ // The algorithm type cannot be selected by customer, hardcoded here.
+ l_part->dpsalg.type = 41;
+
+ // Update internal performance settings for each core on this partition
+ for (j=0; j<l_part->ncores; j++)
+ {
+ l_core_index = l_part->core_list[j];
+ l_perf = &g_amec->proc[0].core[l_core_index % MAX_NUM_CORES].core_perf;
+
+ memset(l_perf->ptr_util_slack_avg_buffer, 0, 2*MAX_UTIL_SLACK_AVG_LEN);
+ memset(l_perf->ptr_util_active_avg_buffer, 0, 2*MAX_UTIL_SLACK_AVG_LEN);
+ l_perf->util_active_core_counter = 0;
+ l_perf->util_slack_core_counter = 0;
+ l_perf->util_slack_accumulator = 0;
+ l_perf->util_active_accumulator = 0;
+ l_perf->ptr_putUtilslack = 0;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_part.h b/src/occ_405/amec/amec_part.h
new file mode 100755
index 0000000..b95909c
--- /dev/null
+++ b/src/occ_405/amec/amec_part.h
@@ -0,0 +1,151 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_part.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 _AMEC_PART_H
+#define _AMEC_PART_H
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+#include <mode.h>
+#include <sensor.h>
+#include <occ_sys_config.h>
+#include <amec_dps.h>
+
+/*----------------------------------------------------------------------------*/
+/* Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Globals */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Defines */
+/*----------------------------------------------------------------------------*/
+
+// Number of cores in system
+#define AMEC_PART_NUM_CORES (MAX_NUM_OCC * MAX_NUM_CORES)
+
+// On a given OCC, only 12 partitions can be defined
+#define AMEC_PART_MAX_PART MAX_NUM_CORES
+
+// Invalid core group ID
+#define AMEC_PART_INVALID_ID 0xFF
+
+/*----------------------------------------------------------------------------*/
+/* Typedef / Enum */
+/*----------------------------------------------------------------------------*/
+
+typedef struct amec_part
+{
+ ///Flag to indicate if the core group should follow the system power policy
+ BOOLEAN follow_sysmode;
+ ///EnergyScale power savings policy
+ OCC_INTERNAL_MODE es_policy;
+ ///Total number of cores in this core group.
+ uint8_t ncores;
+ ///List of cores group. Indices 0 to ncores-1 are valid. Valid values: 0 to
+ ///AMEC_PART_NUM_CORES-1.
+ uint8_t core_list[AMEC_PART_NUM_CORES];
+ ///Partition ID
+ uint8_t id;
+ ///Valid bit (=1 in use, =0 not in use)
+ uint8_t valid;
+ ///Soft min frequency boundary sent by PHYP
+ uint16_t soft_fmin;
+ ///Soft max frequency boundary sent by PHYP
+ uint16_t soft_fmax;
+ ///Power saving state
+ amec_dps_t dpsalg;
+ ///slack utilization sensor
+ sensor_t util2msslack;
+} amec_part_t;
+
+// Main structure that contains the partition configuration for PLPM work.
+typedef struct amec_part_config
+{
+ ///Data structure holding core to partition mapping. The value
+ ///AMEC_PART_INVALID_ID means that a core is not mapped to a partition. A
+ ///value less than that means core is mapped to that partition index.
+ uint16_t core2part[MAX_NUM_CORES];
+
+ ///Data structure holding all active partitions (core groups)
+ amec_part_t part_list[AMEC_PART_MAX_PART];
+} amec_part_config_t;
+
+/*----------------------------------------------------------------------------*/
+/* Function Prototypes */
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Given a core, return a valid partition that owns it, or NULL.
+ *
+ */
+amec_part_t* amec_part_find_by_core(amec_part_config_t* i_config,
+ const uint16_t i_core_index);
+
+/**
+ * This function adds a new core group and should only be called within the
+ * AMEC ISR.
+ *
+ */
+void amec_part_add(uint8_t i_id);
+
+/**
+ * Add a core group.
+ *
+ */
+void amec_part_init(void);
+
+/**
+ * Update the parameter values depending on the DPS mode that
+ * has been selected (Favor Energy or Favor Performance).
+ *
+ */
+void amec_part_update_dps_parameter(amec_part_t* io_part);
+
+/**
+ * Update the internal performance settings for those cores that
+ * belong to the input partition.
+ *
+ */
+void amec_part_update_perf_settings(amec_part_t* io_part);
+
+/**
+ * Update the power mode on all core groups that are following
+ * the system mode.
+ *
+ */
+void AMEC_part_update_sysmode_policy(OCC_MODE i_occ_internal_mode);
+
+/**
+ * Overwrite the tunable parameters used by the DPS algorithms
+ * whenever the Master OCC sends them.
+ *
+ */
+void AMEC_part_overwrite_dps_parameters(void);
+
+#endif //_AMEC_PART_H
diff --git a/src/occ_405/amec/amec_pcap.c b/src/occ_405/amec/amec_pcap.c
new file mode 100755
index 0000000..c742851
--- /dev/null
+++ b/src/occ_405/amec/amec_pcap.c
@@ -0,0 +1,538 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_pcap.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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include "amec_pcap.h"
+#include "amec_sys.h"
+#include "amec_service_codes.h"
+#include <occ_common.h>
+#include <occ_sys_config.h>
+#include <dcom.h>
+#include <trac.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+#define PPB_NOM_DROP_DELAY 4 //ticks
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//Number of ticks to wait before dropping below nominal frequency
+#define PWR_SETTLED_TICKS 4
+//Number of watts power must be below the node power cap before raising
+//ppb_fmax
+#define PDROP_THRESH 0 //TODO: need better value.
+//Number of MHz to raise the proc_pcap_vote for every watt of available power
+//(DCM value should be less than SCM)
+#define PROC_MHZ_PER_WATT 28 //TODO: need better value.
+//Number of MHz to raise ppb_fmax per watt of available power. Depends on
+//number of procs in node.
+#define NODE_MHZ_PER_WATT() \
+ (G_sysConfigData.sys_num_proc_present == 0? \
+ 1: \
+ ((PROC_MHZ_PER_WATT/G_sysConfigData.sys_num_proc_present) == 0? \
+ 1: \
+ PROC_MHZ_PER_WATT/G_sysConfigData.sys_num_proc_present))
+
+//Frequency_step_khz (from global pstate table)/1000
+uint32_t G_mhz_per_pstate=0; //TODO: Maybe there's a better value to initilize it to.
+
+uint8_t G_over_pcap_count=0;
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+//////////////////////////
+// Function Specification
+//
+// Name: amec_pmax_clip_controller
+//
+// Description: Calculate the pmax_clip_freq vote. Initialized to Turbo.
+//
+// Thread: Real Time Loop
+//
+// End Function Specification
+void amec_pmax_clip_controller(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t l_fturbo = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
+ uint32_t l_pmax_clip_freq = g_amec->proc[0].pwr_votes.pmax_clip_freq;
+ Pstate l_pstate = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ //Note: quickPowerDrop interrupts will not preempt the real time loop
+ // interrupt. No locking is needed between the two interrupts.
+ //Note: quickPowerDropLatchAmec represents the failsafe signal on ITEs and
+ // oversubscription signal on non-ITEs.
+
+ // See the oversub event and control oversub in AMEC
+ if(AMEC_INTF_GET_OVERSUBSCRIPTION()&&
+ (g_amec->oversub_status.oversubLatchAmec==FALSE) )
+ {
+ // ISR already did it but still need to do it again here due to
+ // l_pmax_clip_freq is incorrect
+ l_pmax_clip_freq = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+ g_amec->oversub_status.oversubLatchAmec = TRUE;
+ }
+ else if( !AMEC_INTF_GET_OVERSUBSCRIPTION() )
+ {
+ // AMEC doesn't control it and let ISR do it
+ g_amec->oversub_status.oversubLatchAmec = FALSE;
+ }
+
+ if(l_pmax_clip_freq < l_fturbo)
+ {
+ l_pmax_clip_freq += G_mhz_per_pstate;
+
+ if(l_pmax_clip_freq > l_fturbo)
+ {
+ l_pmax_clip_freq = l_fturbo;
+ }
+
+ //call proc_freq2pstate
+ l_pstate = proc_freq2pstate(l_pmax_clip_freq);
+
+ //Set the pmax_clip register via OCI write.
+ amec_oversub_pmax_clip(l_pstate);
+ }
+
+ g_amec->proc[0].pwr_votes.pmax_clip_freq = l_pmax_clip_freq;
+}
+
+//////////////////////////
+// Function Specification
+//
+// Name: amec_pcap_calc
+//
+// Description: Calculate the node power cap and the processor power cap.
+//
+// Thread: Real Time Loop
+//
+// End Function Specification
+void amec_pcap_calc(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ bool l_failsafe_state = AMEC_INTF_GET_FAILSAFE();
+ bool l_oversub_state = 0;
+ uint16_t l_node_pwr = AMECSENSOR_PTR(PWR250US)->sample;
+ uint16_t l_p0_pwr = AMECSENSOR_PTR(PWR250USP0)->sample;
+ int32_t l_avail_power = 0;
+ uint32_t l_proc_fraction = 0;
+ static uint32_t L_prev_node_pcap = 0;
+ static bool l_apss_error_traced = FALSE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ //TRAC_INFO("amec_pcap_calc: Calculate active_node_pcap, and nom_pcap_fmin.");
+ l_oversub_state = AMEC_INTF_GET_OVERSUBSCRIPTION();
+
+ //Set the active_node_pcap in g_amec.
+ if(TRUE == l_failsafe_state)
+ {
+ //Set active_node_pcap to soft min pcap since failsafe is on
+ g_amec->pcap.active_node_pcap = G_sysConfigData.pcap.soft_min_pcap;
+ }
+ else if(TRUE == l_oversub_state)
+ {
+ g_amec->pcap.active_node_pcap = g_amec->pcap.ovs_node_pcap;
+ }
+ else
+ {
+ g_amec->pcap.active_node_pcap = g_amec->pcap.norm_node_pcap;
+ }
+
+ //Trace whenever the node pcap changes
+ if(L_prev_node_pcap != g_amec->pcap.active_node_pcap)
+ {
+ TRAC_IMP("amec_pcap_calc: Node pcap set to %d watts.",
+ g_amec->pcap.active_node_pcap);
+ L_prev_node_pcap = g_amec->pcap.active_node_pcap;
+
+ // set this pcap as valid (needed by master for comparison)
+ g_amec->pcap_valid = 1;
+ }
+
+ l_avail_power = g_amec->pcap.active_node_pcap - l_node_pwr;
+ if(l_node_pwr != 0)
+ {
+ l_proc_fraction = ((uint32_t)(l_p0_pwr) << 16)/l_node_pwr;
+ if(l_apss_error_traced)
+ {
+ TRAC_ERR("PCAP: PWR250US sensor is no longer 0.");
+ l_apss_error_traced = FALSE;
+ }
+ }
+ else
+ {
+ if(!l_apss_error_traced)
+ {
+ TRAC_ERR("PCAP: PWR250US sensor is showing a value of 0.");
+ l_apss_error_traced = TRUE;
+ }
+ }
+
+ g_amec->pcap.active_proc_pcap = l_p0_pwr + ((l_proc_fraction * l_avail_power) >> 16);
+
+ //TRAC_INFO("PCAP: calculated active proc pcap: avail_power[0x%X],proc_fraction[0x%X],"
+ // "active_proc_pcap[0x%X].",l_avail_power,l_proc_fraction,g_amec->pcap.active_proc_pcap);
+
+ //NOTE: Power capping will not affect nominal cores unless a customer power cap is set below the
+ // max pcap or oversubscription occurs.
+ // However, nominal cores will drop below nominal if ppb_fmax drops below nominal.
+ if(g_amec->pcap.active_node_pcap < G_sysConfigData.pcap.max_pcap)
+ {
+ g_amec->proc[0].pwr_votes.nom_pcap_fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+ }
+ else
+ {
+ g_amec->proc[0].pwr_votes.nom_pcap_fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL];
+ }
+}
+
+//////////////////////////
+// Function Specification
+//
+// Name: amec_pcap_controller
+//
+// Description: Execute the processor Pcap control loop.
+//
+// Thread: Real Time Loop
+//
+// End Function Specification
+void amec_pcap_controller(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ int32_t l_power_avail = 0;
+ int32_t l_proc_pcap_vote = g_amec->proc[0].pwr_votes.proc_pcap_vote;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ l_power_avail = g_amec->pcap.active_proc_pcap - AMECSENSOR_PTR(PWR250USP0)->sample;
+
+ if(l_proc_pcap_vote > g_amec->proc[0].pwr_votes.nom_pcap_fmin)
+ {
+ l_proc_pcap_vote = g_amec->proc[0].core_max_freq +
+ (PROC_MHZ_PER_WATT * l_power_avail);
+ }
+ else
+ {
+ l_proc_pcap_vote += (PROC_MHZ_PER_WATT * l_power_avail);
+ }
+
+ if(l_proc_pcap_vote > G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO])
+ {
+ l_proc_pcap_vote = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
+ }
+
+ if(l_proc_pcap_vote < G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY])
+ {
+ l_proc_pcap_vote = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+ }
+
+ //Power capping for nominal cores is not allowed to drop frequency below nom_pcap_fmin
+ if(l_proc_pcap_vote < g_amec->proc[0].pwr_votes.nom_pcap_fmin)
+ {
+ g_amec->proc[0].pwr_votes.proc_pcap_nom_vote = g_amec->proc[0].pwr_votes.nom_pcap_fmin;
+ }
+ else
+ {
+ g_amec->proc[0].pwr_votes.proc_pcap_nom_vote = l_proc_pcap_vote;
+ }
+
+ g_amec->proc[0].pwr_votes.proc_pcap_vote = l_proc_pcap_vote;
+}
+
+//////////////////////////
+// Function Specification
+//
+// Name: amec_ppb_fmax_calc
+//
+// Description: Calculate the Performance Preserving Bounds (PPB) vote.
+//
+// Thread: Real Time Loop
+//
+// End Function Specification
+void amec_ppb_fmax_calc(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ int32_t l_power_avail = 0;
+ bool l_continue = TRUE; //Used to break from code if needed.
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ //Set the slaves local copy of ppb_fmax to that received from Master OCC.
+ g_amec->proc[0].pwr_votes.ppb_fmax = G_dcom_slv_inbox_doorbell_rx.ppb_fmax;
+ // For debug
+ sensor_update( AMECSENSOR_PTR(PROBE250US0), g_amec->proc[0].pwr_votes.ppb_fmax);
+
+ //CALCULATION done by MASTER OCC only.
+ if(OCC_MASTER == G_occ_role)
+ {
+ //Power available is the ActiveNodePower - PowerDropThreshold - ActualPwr
+ l_power_avail = g_amec->pcap.active_node_pcap - PDROP_THRESH - AMECSENSOR_PTR(PWR250US)->sample;
+
+ //Note: The PWR250US value is read over the SPI bus, which has no error
+ //detection. In order to prevent a single bad SPI transfer from causing
+ //OCC to lower nominal core frequencies, we require the power to be over
+ //the pcap for PPB_NOM_DROP_DELAY ticks before lowering PPB Fmax below
+ //Fnom.
+ if((g_amec->proc[0].pwr_votes.ppb_fmax == G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL])
+ && (l_power_avail <=0))
+ {
+ if(G_over_pcap_count < PPB_NOM_DROP_DELAY)
+ {
+ G_over_pcap_count++;
+ l_continue = FALSE;
+ }
+ }
+ else
+ {
+ G_over_pcap_count = 0;
+ }
+
+ //Only run once every 4 ticks (1ms) to allow time for power hogging
+ //chips to drop power and power starved chips to raise power.
+ if(l_continue && (0 == (G_current_tick & 0x3)))
+ {
+ if(l_power_avail <= 0)
+ {
+ G_sysConfigData.master_ppb_fmax -= G_mhz_per_pstate;
+ }
+ else
+ {
+ G_sysConfigData.master_ppb_fmax += NODE_MHZ_PER_WATT() * l_power_avail;
+ }
+
+ if(G_sysConfigData.master_ppb_fmax > G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO])
+ {
+ G_sysConfigData.master_ppb_fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
+ }
+
+ if(G_sysConfigData.master_ppb_fmax < G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY])
+ {
+ G_sysConfigData.master_ppb_fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+ }
+ }
+ }//End of Master code
+}
+
+//////////////////////////
+// Function Specification
+//
+// Name: amec_conn_oc_controller
+//
+// Description: Handle Over Current. Useful on ITE system only.
+// Design uses 2 step procedure when OC is detected.
+// 1) Lower all cores to Fnom
+// 2) If still asserted after PWR_SETTLED_TICKS, lower all cores to Fmin
+//
+// Thread: Real Time Loop
+//
+// End Function Specification
+void amec_conn_oc_controller(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ errlHndl_t l_err = NULL;
+ static uint8_t L_asserted_count = 0;
+ static bool L_error_logged = FALSE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ //If no overcurrent pins are set, then set vote to Turbo
+ if(G_conn_oc_pins_bitmap == 0)
+ {
+ g_amec->proc[0].pwr_votes.conn_oc_vote = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
+ }
+ else
+ {
+ //Check if any of the OC gpio pins are set.
+ //TODO: G_conn_oc_pins_bitmap should be populated with data sent by TMGT.
+ if((G_conn_oc_pins_bitmap & ~(G_apss_pwr_meas.gpio[0])) == 0)
+ {
+ //Reset counter
+ L_asserted_count = 0;
+
+ g_amec->proc[0].pwr_votes.conn_oc_vote += G_mhz_per_pstate;
+
+ //Verify that vote is not greater than turbo.
+ if(g_amec->proc[0].pwr_votes.conn_oc_vote > G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO])
+ {
+ g_amec->proc[0].pwr_votes.conn_oc_vote = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
+ }
+ }
+ else if(L_asserted_count < PWR_SETTLED_TICKS)
+ {
+ g_amec->proc[0].pwr_votes.conn_oc_vote = G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL];
+ L_asserted_count++;
+
+ //Log an informational error
+ TRAC_ERR("Connector overcurrent pins still asserted. Count=%i.",L_asserted_count);
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_PCAP_CONN_OC_CONTROLLER
+ * @reasoncode CONNECTOR_OC_PINS_WARNING
+ * @userdata1 OC pin bitmap
+ * @userdata2 APSS power measure gpio state
+ * @devdesc The connector overcurrent pins are still asserted.
+ *
+ */
+
+ //TODO: ADD ACTION FLAG for manufacturing error to log it as predictive.
+ if(!L_error_logged) //only log this error once
+ {
+ L_error_logged = TRUE;
+ l_err = createErrl(
+ AMEC_PCAP_CONN_OC_CONTROLLER, //modId
+ CONNECTOR_OC_PINS_WARNING, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_INFORMATIONAL, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ G_conn_oc_pins_bitmap, //userdata1
+ G_apss_pwr_meas.gpio[0] //userdata2
+ );
+
+ commitErrl( &l_err);
+ }
+ }
+ else //Asserted count reached or exceeded PWR_SETTLED_TICKS.
+ {
+ g_amec->proc[0].pwr_votes.conn_oc_vote = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+
+ if(CURRENT_MODE() == OCC_MODE_NOMINAL)
+ {
+ //Log a predictive error
+ TRAC_ERR("Connector overcurrent pins still asserted after max ticks. Logging error.");
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_PCAP_CONN_OC_CONTROLLER
+ * @reasoncode CONNECTOR_OC_PINS_FAILURE
+ * @userdata1 OC pin bitmap
+ * @userdata2 APSS power measure gpio state
+ * @devdesc The connector overcurrent pins are asserted for too long.
+ *
+ */
+
+ l_err = createErrl(
+ AMEC_PCAP_CONN_OC_CONTROLLER, //modId
+ CONNECTOR_OC_PINS_FAILURE, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ G_conn_oc_pins_bitmap, //userdata1
+ G_apss_pwr_meas.gpio[0] //userdata2
+ );
+
+ commitErrl( &l_err);
+
+ //Request safe mode without retries.
+ //TODO: add code to request safe mode with no retries.
+ }
+ }
+ }
+}
+
+//////////////////////////
+// Function Specification
+//
+// Name: amec_power_control
+//
+// Description: Main function for power control loop.
+//
+// Thread: Real Time Loop
+//
+// End Function Specification
+void amec_power_control(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Call amec pmax clip controller to control the Pmax_clip register setting
+ // and voting box input.
+ amec_pmax_clip_controller();
+
+ // Calculate the power cap for the processor and the power capping limit
+ // for nominal cores.
+ amec_pcap_calc();
+
+ // Calculate the voting box input frequency for staying with the current pcap
+ amec_pcap_controller();
+
+ // Calculate the performance preserving bounds voting box input frequency.
+ amec_ppb_fmax_calc();
+
+ // Check for connector overcurrent condition and calculate voting box input frequency.
+ amec_conn_oc_controller();
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_pcap.h b/src/occ_405/amec/amec_pcap.h
new file mode 100755
index 0000000..47a065b
--- /dev/null
+++ b/src/occ_405/amec/amec_pcap.h
@@ -0,0 +1,80 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_pcap.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 _AMEC_PCAP_H
+#define _AMEC_PCAP_H
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <errl.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//Number of watts power must be below the node power cap before raising
+//ppb_fmax
+#define PDROP_THRESH 0 //TODO: need better value.
+
+//Structure used in g_amec
+typedef struct amec_pcap
+{
+ uint16_t ovs_node_pcap; //Oversub node power cap in 1W units
+ uint16_t norm_node_pcap; //Normal node power cap in 1W units
+ uint16_t active_node_pcap; //Currently active node power cap in 1W units
+ uint16_t active_proc_pcap; //Currently active proc power cap in 1W units
+} amec_pcap_t;
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// Calls all power control algorithms
+void amec_power_control();
+
+#endif
+
diff --git a/src/occ_405/amec/amec_perfcount.c b/src/occ_405/amec/amec_perfcount.c
new file mode 100755
index 0000000..da37d40
--- /dev/null
+++ b/src/occ_405/amec/amec_perfcount.c
@@ -0,0 +1,134 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_perfcount.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 */
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+#include <string.h>
+#include <common_types.h>
+#include <sensor.h>
+#include <amec_sys.h>
+#include <amec_part.h>
+#include <amec_perfcount.h>
+
+/*----------------------------------------------------------------------------*/
+/* Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Globals */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Typedef / Enum */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Code */
+/*----------------------------------------------------------------------------*/
+
+// Function Specification
+//
+// Name: amec_calc_dps_util_counters
+//
+// Description: Calculate the performance counter for a core.
+//
+// End Function Specification
+void amec_calc_dps_util_counters(const uint8_t i_core_id)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ amec_part_t *l_part = NULL;
+ amec_core_perf_counter_t *l_perf = NULL;
+ sensor_ptr_t l_sensor = NULL;
+ uint16_t l_utilization = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ l_perf = &g_amec->proc[0].core[i_core_id].core_perf;
+ // Read sensor for this core
+ l_sensor = AMECSENSOR_ARRAY_PTR(UTIL2MSP0C0, i_core_id);
+ l_utilization = l_sensor->sample;
+ l_part = amec_part_find_by_core(&g_amec->part_config, i_core_id);
+
+ // Type 41 input: Check if core's utilization is within
+ // epsilon of the slack threshold: if yes declare the core
+ // active
+ if (l_part != NULL)
+ {
+ if (l_utilization > (l_part->dpsalg.tlutil - l_part->dpsalg.epsilon_perc))
+ {
+ // indicate core is active
+ l_perf->util_active_core_counter++;
+
+ if (l_utilization < l_part->dpsalg.tlutil)
+ {
+ // indicate core has some slack
+ l_perf->util_slack_core_counter++;
+ }
+ }
+ }
+}
+
+// Function Specification
+//
+// Name: amec_core_perf_counter_ctor
+//
+// Description: Build the performance counter for a core.
+//
+// End Function Specification
+amec_core_perf_counter_t* amec_core_perf_counter_ctor(amec_core_perf_counter_t* i_this_ptr,
+ const uint8_t i_proc_id,
+ const uint8_t i_core_id)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ //zero everything out, regardless of when we were called
+ memset(i_this_ptr, 0x00, sizeof(amec_core_perf_counter_t));
+
+ // Create space for per-core active and slack counts (for DPS #41 algorithm)
+ memset(i_this_ptr->ptr_util_slack_avg_buffer, 0,
+ (uint32_t)(2*MAX_UTIL_SLACK_AVG_LEN));
+ memset(i_this_ptr->ptr_util_active_avg_buffer, 0,
+ (uint32_t)(2*MAX_UTIL_SLACK_AVG_LEN));
+
+ // DPS frequency request. Choose highest performance by default.
+ i_this_ptr->dps_freq_request = UINT16_MAX; // input to core freq voting box
+
+ //pass out i_this_ptr in case we're allocating this dynamically
+ return i_this_ptr;
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_perfcount.h b/src/occ_405/amec/amec_perfcount.h
new file mode 100755
index 0000000..49eb20c
--- /dev/null
+++ b/src/occ_405/amec/amec_perfcount.h
@@ -0,0 +1,89 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_perfcount.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 _AMEC_PERFCOUNT_H
+#define _AMEC_PERFCOUNT_H
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Globals */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Defines */
+/*----------------------------------------------------------------------------*/
+#define MAX_UTIL_SLACK_AVG_LEN 64 // Max # of samples in utilization slack averaging buffer
+
+/*----------------------------------------------------------------------------*/
+/* Typedef / Enum */
+/*----------------------------------------------------------------------------*/
+
+/// Core Performance Counter Model
+typedef struct amec_core_perf_counter
+{
+ ///32-bit accumulator of util_slack counter
+ uint32_t util_slack_accumulator;
+ ///32-bit accumulator of util_active counter
+ uint32_t util_active_accumulator;
+ ///Circular buffer pointer to put Utilslack signal
+ uint16_t ptr_putUtilslack;
+ ///Frequency request
+ uint16_t dps_freq_request;
+ ///32-bit pointer to utilization slack averaging buffer
+ uint8_t ptr_util_slack_avg_buffer[2*MAX_UTIL_SLACK_AVG_LEN];
+ ///32-bit pointer to utilization active averaging buffer
+ uint8_t ptr_util_active_avg_buffer[2*MAX_UTIL_SLACK_AVG_LEN];
+ ///8-bit counter of cores that are active (utilization>CPU_utilization_threshold)
+ uint8_t util_active_core_counter;
+ ///8-bit counter of cores with slack (utilization<type 1 alg UTIL tlutil)
+ uint8_t util_slack_core_counter;
+}amec_core_perf_counter_t;
+
+/*----------------------------------------------------------------------------*/
+/* Function Prototypes */
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Calculate the performance counter for a core
+ *
+ */
+void amec_calc_dps_util_counters(const uint8_t i_core_id);
+
+/**
+ * Build the performance counter for a core
+ *
+ */
+amec_core_perf_counter_t* amec_core_perf_counter_ctor(amec_core_perf_counter_t* i_this_ptr,
+ const uint8_t i_proc_id,
+ const uint8_t i_core_id);
+
+#endif
diff --git a/src/occ_405/amec/amec_sensors_centaur.c b/src/occ_405/amec/amec_sensors_centaur.c
new file mode 100644
index 0000000..2679bc9
--- /dev/null
+++ b/src/occ_405/amec/amec_sensors_centaur.c
@@ -0,0 +1,686 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_sensors_centaur.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 */
+
+/******************************************************************************/
+/* includes */
+/******************************************************************************/
+#include <occ_common.h>
+#include <ssx.h>
+#include <errl.h> // Error logging
+#include "sensor.h"
+#include "rtls.h"
+#include "occ_sys_config.h"
+#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE
+#include "dcom.h"
+#include "centaur_data.h"
+#include "amec_smh.h"
+#include "amec_slave_smh.h"
+#include <trac.h>
+#include "amec_sys.h"
+#include "sensor_enum.h"
+#include "amec_service_codes.h"
+#include <amec_sensors_centaur.h>
+
+/******************************************************************************/
+/* Globals */
+/******************************************************************************/
+cent_sensor_flags_t G_dimm_overtemp_bitmap = {0};
+cent_sensor_flags_t G_dimm_temp_updated_bitmap = {0};
+uint8_t G_cent_overtemp_bitmap = 0;
+uint8_t G_cent_temp_updated_bitmap = 0;
+extern uint8_t G_centaur_needs_recovery;
+extern uint8_t G_centaur_nest_lfir6;
+
+/******************************************************************************/
+/* Forward Declarations */
+/******************************************************************************/
+void amec_update_dimm_dts_sensors(MemData * i_sensor_cache, uint8_t i_centaur);
+void amec_update_centaur_dts_sensors(MemData * i_sensor_cache, uint8_t i_centaur);
+void amec_perfcount_getmc( MemData * i_sensor_cache, uint8_t i_centaur);
+
+/******************************************************************************/
+/* Code */
+/******************************************************************************/
+
+// Function Specification
+//
+// Name: amec_update_dimm_dts_sensors
+//
+// Description: Updates sensors that have data grabbed by the fast core data
+// task.
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_update_centaur_sensors(uint8_t i_centaur)
+{
+ if(CENTAUR_PRESENT(i_centaur))
+ {
+ MemData * l_sensor_cache = cent_get_centaur_data_ptr(i_centaur);
+ if(CENTAUR_UPDATED(i_centaur))
+ {
+ amec_update_dimm_dts_sensors(l_sensor_cache, i_centaur);
+ amec_update_centaur_dts_sensors(l_sensor_cache, i_centaur);
+ }
+ amec_perfcount_getmc(l_sensor_cache, i_centaur);
+ CLEAR_CENTAUR_UPDATED(i_centaur);
+ }
+}
+
+// Function Specification
+//
+// Name: amec_update_dimm_dts_sensors
+//
+// Description: Updates sensors that have data grabbed by the fast core data
+// task.
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_update_dimm_dts_sensors(MemData * i_sensor_cache, uint8_t i_centaur)
+{
+#define MIN_VALID_DIMM_TEMP 1
+#define MAX_VALID_DIMM_TEMP 125 //according to Mike Pardiek
+#define MAX_MEM_TEMP_CHANGE 2
+
+ uint32_t k, l_hottest_dimm_temp;
+ uint16_t l_dts[NUM_DIMMS_PER_CENTAUR] = {0};
+ uint32_t l_hottest_dimm_loc = NUM_DIMMS_PER_CENTAUR;
+ uint32_t l_sens_status;
+ int32_t l_dimm_temp, l_prev_temp;
+ static uint8_t L_ran_once[MAX_NUM_CENTAURS] = {FALSE};
+
+ // Harvest thermal data for all dimms
+ for(k=0; k < NUM_DIMMS_PER_CENTAUR; k++)
+ {
+ if(!CENTAUR_SENSOR_ENABLED(i_centaur, k))
+ {
+ continue;
+ }
+
+ l_sens_status = i_sensor_cache->scache.dimm_thermal_sensor[k].fields.status;
+ fru_temp_t* l_fru = &g_amec->proc[0].memctl[i_centaur].centaur.dimm_temps[k];
+
+ l_dimm_temp = i_sensor_cache->scache.dimm_thermal_sensor[k].fields.temperature;
+ l_prev_temp = l_fru->cur_temp;
+ if(!l_prev_temp)
+ {
+ l_prev_temp = l_dimm_temp;
+ }
+
+ //Check DTS status bits.
+ if(l_sens_status == DIMM_SENSOR_STATUS_VALID_NEW)
+ {
+ //make sure temperature is within a 'reasonable' range.
+ if(l_dimm_temp < MIN_VALID_DIMM_TEMP ||
+ l_dimm_temp > MAX_VALID_DIMM_TEMP)
+ {
+ //set a flag so that if we end up logging an error we have something to debug why
+ l_fru->flags |= FRU_TEMP_OUT_OF_RANGE;
+ l_dts[k] = l_prev_temp;
+ }
+ else
+ {
+ //don't allow temp to change more than is reasonable for 2ms
+ if(l_dimm_temp > (l_prev_temp + MAX_MEM_TEMP_CHANGE))
+ {
+ l_dts[k] = l_prev_temp + MAX_MEM_TEMP_CHANGE;
+ if(!l_fru->flags)
+ {
+ TRAC_INFO("dimm temp rose faster than reasonable: cent[%d] dimm[%d] prev[%d] cur[%d]",
+ i_centaur, k, l_prev_temp, l_dimm_temp);
+ l_fru->flags |= FRU_TEMP_FAST_CHANGE;
+ }
+ }
+ else if (l_dimm_temp < (l_prev_temp - MAX_MEM_TEMP_CHANGE))
+ {
+ l_dts[k] = l_prev_temp - MAX_MEM_TEMP_CHANGE;
+ if(!l_fru->flags)
+ {
+ TRAC_INFO("dimm temp fell faster than reasonable: cent[%d] dimm[%d] prev[%d] cur[%d]",
+ i_centaur, k, l_prev_temp, l_dimm_temp);
+ l_fru->flags |= FRU_TEMP_FAST_CHANGE;
+ }
+ }
+ else //reasonable amount of change occurred
+ {
+ l_dts[k] = l_dimm_temp;
+ l_fru->flags &= ~FRU_TEMP_FAST_CHANGE;
+ }
+
+ //Notify thermal thread that temperature has been updated
+ G_dimm_temp_updated_bitmap.bytes[i_centaur] |= DIMM_SENSOR0 >> k;
+
+ //clear error flags
+ l_fru->flags &= FRU_TEMP_FAST_CHANGE;
+ }
+ }
+ else //status was VALID_OLD, ERROR, or STALLED
+ {
+ //convert status number to a flag
+ uint8_t l_status_flag = 1 << l_sens_status;
+
+ if(L_ran_once[i_centaur])
+ {
+ //Trace the error if we haven't traced it already for this sensor
+ if((l_sens_status != DIMM_SENSOR_STATUS_VALID_OLD) &&
+ !(l_status_flag & l_fru->flags))
+ {
+ TRAC_INFO("Centaur%d sensor%d error: %d", i_centaur, k, l_sens_status);
+ }
+
+ l_fru->flags |= l_status_flag;
+ }
+
+ //use last temperature
+ l_dts[k] = l_prev_temp;
+
+ //request recovery (disable and re-enable sensor cache collection)
+ if(l_sens_status == DIMM_SENSOR_STATUS_ERROR)
+ {
+ G_centaur_needs_recovery |= CENTAUR0_PRESENT_MASK >> i_centaur;
+ }
+ }
+
+ //Check if at or above the error temperature
+ if(l_dts[k] >= g_amec->thermaldimm.ot_error)
+ {
+ //Set a bit so that this dimm can be called out by the thermal thread
+ G_dimm_overtemp_bitmap.bytes[i_centaur] |= 1 << k;
+ }
+ }
+
+ // Find hottest temperature from all DIMMs for this centaur
+ for(l_hottest_dimm_temp = 0, k = 0; k < NUM_DIMMS_PER_CENTAUR; k++)
+ {
+ if(l_dts[k] > l_hottest_dimm_temp)
+ {
+ l_hottest_dimm_temp = l_dts[k];
+ l_hottest_dimm_loc = k;
+ }
+ g_amec->proc[0].memctl[i_centaur].centaur.dimm_temps[k].cur_temp = l_dts[k];
+ }
+
+ amec_centaur_t* l_centaur_ptr = &g_amec->proc[0].memctl[i_centaur].centaur;
+
+ //only update location if hottest dimm temp is greater than previous maximum
+ if(l_hottest_dimm_temp > l_centaur_ptr->tempdimmax.sample_max)
+ {
+ sensor_update(&l_centaur_ptr->locdimmax, l_hottest_dimm_loc);
+ }
+
+ //update the max dimm temperature sensor for this centaur
+ sensor_update(&l_centaur_ptr->tempdimmax, l_hottest_dimm_temp);
+
+ L_ran_once[i_centaur] = TRUE;
+ AMEC_DBG("Centaur[%d]: HotDimm=%d\n",i_centaur,l_hottest_dimm_temp);
+}
+
+
+// Function Specification
+//
+// Name: amec_update_centaur_dts_sensors
+//
+// Description: Updates sensors taht have data grabbed by the fast core data
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_update_centaur_dts_sensors(MemData * i_sensor_cache, uint8_t i_centaur)
+{
+#define MIN_VALID_CENT_TEMP 1
+#define MAX_VALID_CENT_TEMP 125 //according to Mike Pardiek
+#define CENT_SENSOR_STATUS_VALID 0x0001
+#define CENT_SENSOR_TEMP_MASK 0xfff0
+
+ uint16_t l_dts, l_sens_value0, l_sens_value1;
+ uint16_t l_sens_status0, l_sens_status1, l_sens_status;
+ uint16_t l_sens_temp0, l_sens_temp1, l_cent_temp;
+ int32_t l_prev_temp;
+ static uint8_t L_ran_once[MAX_NUM_CENTAURS] = {FALSE};
+
+ l_sens_value0 = i_sensor_cache->scache.centaur_thermal_sensor[0].value;
+ l_sens_value1 = i_sensor_cache->scache.centaur_thermal_sensor[1].value;
+ l_sens_status0 = l_sens_value0 & CENT_SENSOR_STATUS_VALID;
+ l_sens_status1 = l_sens_value1 & CENT_SENSOR_STATUS_VALID;
+ l_sens_temp0 = (l_sens_status0)? (l_sens_value0 & CENT_SENSOR_TEMP_MASK) >> 4:
+ 0;
+ l_sens_temp1 = (l_sens_status1)? (l_sens_value1 & CENT_SENSOR_TEMP_MASK) >> 4:
+ 0;
+ l_sens_status = l_sens_status0 | l_sens_status1;
+ l_cent_temp = (l_sens_temp0 > l_sens_temp1)? l_sens_temp0: l_sens_temp1;
+
+ fru_temp_t* l_fru = &g_amec->proc[0].memctl[i_centaur].centaur.centaur_hottest;
+
+ l_prev_temp = l_fru->cur_temp;
+ if(!l_prev_temp)
+ {
+ l_prev_temp = l_cent_temp;
+ }
+
+ //Check DTS status bits and NEST LFIR bit 6 for a valid temperature.
+ if(l_sens_status == CENT_SENSOR_STATUS_VALID &&
+ !(G_centaur_nest_lfir6 & (CENTAUR0_PRESENT_MASK >> i_centaur)))
+ {
+ //make sure temperature is within a 'reasonable' range.
+ if(l_cent_temp < MIN_VALID_CENT_TEMP ||
+ l_cent_temp > MAX_VALID_CENT_TEMP)
+ {
+ //set a flag so that if we end up logging an error we have something to debug why
+ l_fru->flags |= FRU_TEMP_OUT_OF_RANGE;
+ l_dts = l_prev_temp;
+ }
+ else
+ {
+ //don't allow temp to change more than is reasonable for 2ms
+ if(l_cent_temp > (l_prev_temp + MAX_MEM_TEMP_CHANGE))
+ {
+ l_dts = l_prev_temp + MAX_MEM_TEMP_CHANGE;
+ if(!l_fru->flags)
+ {
+ TRAC_INFO("centaur temp rose faster than reasonable: cent[%d] prev[%d] cur[%d]",
+ i_centaur, l_prev_temp, l_cent_temp);
+ l_fru->flags |= FRU_TEMP_FAST_CHANGE;
+ }
+ }
+ else if (l_cent_temp < (l_prev_temp - MAX_MEM_TEMP_CHANGE))
+ {
+ l_dts = l_prev_temp - MAX_MEM_TEMP_CHANGE;
+ if(!l_fru->flags)
+ {
+ TRAC_INFO("centaur temp fell faster than reasonable: cent[%d] prev[%d] cur[%d]",
+ i_centaur, l_prev_temp, l_cent_temp);
+ l_fru->flags |= FRU_TEMP_FAST_CHANGE;
+ }
+ }
+ else //reasonable amount of change occurred
+ {
+ l_dts = l_cent_temp;
+ l_fru->flags &= ~FRU_TEMP_FAST_CHANGE;
+ }
+
+ //Notify thermal thread that temperature has been updated
+ G_cent_temp_updated_bitmap |= CENTAUR0_PRESENT_MASK >> i_centaur;
+
+ //clear error flags
+ l_fru->flags &= FRU_TEMP_FAST_CHANGE;
+ }
+ }
+ else //status was INVALID
+ {
+ if(L_ran_once[i_centaur])
+ {
+ //Trace the error if we haven't traced it already for this sensor
+ //and this wasn't only caused by LFIR[6] (which is traced elsewhere).
+ if(!(l_fru->flags & FRU_SENSOR_STATUS_INVALID) &&
+ !(l_sens_status == CENT_SENSOR_STATUS_VALID))
+ {
+ TRAC_INFO("Centaur%d temp invalid. nest_lfir6=0x%02x", i_centaur, G_centaur_nest_lfir6);
+ }
+
+ l_fru->flags |= FRU_SENSOR_STATUS_INVALID;
+
+ if(G_centaur_nest_lfir6 & (CENTAUR0_PRESENT_MASK >> i_centaur))
+ {
+ l_fru->flags |= FRU_SENSOR_CENT_NEST_FIR6;
+ }
+ }
+
+ //use last temperature
+ l_dts = l_prev_temp;
+ }
+
+ L_ran_once[i_centaur] = TRUE;
+
+ //Check if at or above the error temperature
+ if(l_dts >= g_amec->thermalcent.ot_error)
+ {
+ //Set a bit so that this dimm can be called out by the thermal thread
+ G_cent_overtemp_bitmap |= (CENTAUR0_PRESENT_MASK >> i_centaur);
+ }
+
+ // Update Interim Data - later this will get picked up to form centaur sensor
+ g_amec->proc[0].memctl[i_centaur].centaur.centaur_hottest.cur_temp = l_dts;
+
+ AMEC_DBG("Centaur[%d]: HotCentaur=%d\n",i_centaur,l_dts);
+}
+
+
+// Function Specification
+//
+// Name: amec_update_centaur_temp_sensors
+//
+// Description: Updates thermal sensors that have data grabbed by the centaur.
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_update_centaur_temp_sensors(void)
+{
+ uint32_t k, l_hot;
+
+ // -----------------------------------------------------------
+ // Find hottest temperature from all centaurs for this P8 chip
+ // -----------------------------------------------------------
+ for(l_hot = 0, k=0; k < MAX_NUM_CENTAURS; k++)
+ {
+ if(g_amec->proc[0].memctl[k].centaur.centaur_hottest.cur_temp > l_hot)
+ {
+ l_hot = g_amec->proc[0].memctl[k].centaur.centaur_hottest.cur_temp;
+ }
+ }
+ sensor_update(&g_amec->proc[0].temp2mscent,l_hot);
+ AMEC_DBG("HotCentaur=%d\n",l_hot);
+
+ // --------------------------------------------------------
+ // Find hottest temperature from all DIMMs for this P8 chip
+ // --------------------------------------------------------
+ for(l_hot = 0, k=0; k < MAX_NUM_CENTAURS; k++)
+ {
+ if(g_amec->proc[0].memctl[k].centaur.tempdimmax.sample > l_hot)
+ {
+ l_hot = g_amec->proc[0].memctl[k].centaur.tempdimmax.sample;
+ }
+ }
+ sensor_update(&g_amec->proc[0].temp2msdimm,l_hot);
+ AMEC_DBG("HotDimm=%d\n",l_hot);
+}
+
+
+// Function Specification
+//
+// Name: amec_perfcount_getmc
+//
+// Description: Updates performance sensors that have data grabbed by the
+// centaur.
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_perfcount_getmc( MemData * i_sensor_cache,
+ uint8_t i_centaur)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ UINT32 tempu = 0;
+ UINT32 templ = 0;
+ UINT32 temp32new = 0;
+ UINT32 temp32 = 0;
+ UINT16 tempreg = 0;
+ UINT16 tempreg2 = 0;
+ uint8_t i_mc_id = 0;
+ #define AMECSENSOR_PORTPAIR_PTR(sensor_base,idx,idx2) \
+ (&(g_amec->proc[0].memctl[idx].centaur.portpair[idx2].sensor_base))
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ MemData * l_sensor_cache = i_sensor_cache;
+
+ for(i_mc_id=0; i_mc_id<2; i_mc_id++)
+ {
+ if (i_mc_id == 0)
+ {
+ tempu = l_sensor_cache->scache.mba01_rd;
+ templ = l_sensor_cache->scache.mba01_wr;
+ }
+ else
+ {
+ tempu = l_sensor_cache->scache.mba23_rd;
+ templ = l_sensor_cache->scache.mba23_wr;
+ }
+
+ // ---------------------------------------------------------------------------
+ // Interim Calculation: MWR2MSP0Mx (0.01 Mrps) Memory write requests per sec
+ // ---------------------------------------------------------------------------
+
+ // Extract write bandwidth
+ temp32new = (templ); // left shift into top 20 bits of 32 bits
+
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.wr_cnt_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.wr_cnt_accum = temp32new; // Save latest accumulator away for next time
+
+ // Read every 2 ms....to convert to 0.01 Mrps = ((2ms read * 500)/10000)
+ tempreg = ((temp32*5)/100);
+
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.memwrite2ms = tempreg;
+
+ // -------------------------------------------------------------------------
+ // Interim Calculation: MRD2MSP0Mx (0.01 Mrps) Memory read requests per sec
+ // -------------------------------------------------------------------------
+
+ // Extract read bandwidth
+ temp32new = (tempu); // left shift into top 20 bits of 32 bits
+
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.rd_cnt_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.rd_cnt_accum = temp32new; // Save latest accumulator away for next time
+
+ // Read every 2 ms....to convert to 0.01 Mrps = ((2ms read * 500)/10000)
+ tempreg = ((temp32*5)/100);
+
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.memread2ms = tempreg;
+
+ // Go after second MC performance counter (power ups and activations)
+ if (i_mc_id == 0)
+ {
+ tempu = l_sensor_cache->scache.mba01_act;
+ templ = l_sensor_cache->scache.mba01_powerups;
+ }
+ else
+ {
+ tempu = l_sensor_cache->scache.mba23_act;
+ templ = l_sensor_cache->scache.mba23_powerups;
+ }
+
+ // ----------------------------------------------------------------
+ // Sensor: MPU2MSP0Mx (0.01 Mrps) Memory power-up requests per sec
+ // ----------------------------------------------------------------
+ // Extract power up count
+ temp32new = (templ); // left shift into top 20 bits of 32 bits
+
+ // For DD1.0, we only have 1 channel field that we use; DD2.0 we need to add another channel
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.pwrup_cnt_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.pwrup_cnt_accum = temp32new; // Save latest accumulator away for next time
+ tempreg=(UINT16)(temp32>>12); // Select upper 20 bits
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.pwrup_cnt=(UINT16)tempreg;
+ sensor_update(AMECSENSOR_PORTPAIR_PTR(mpu2ms,i_centaur,i_mc_id), tempreg);
+
+ // -------------------------------------------------------------------
+ // Sensor: MAC2MSP0Mx (0.01 Mrps) Memory activation requests per sec
+ // -------------------------------------------------------------------
+ // Extract activation count
+ temp32 = templ;
+ temp32 += tempu;
+
+ temp32new = (temp32); // left shift into top 20 bits of 32 bits
+ // For DD1.0, we only have 1 channel field that we use; DD2.0 we need to add another channel
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.act_cnt_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.act_cnt_accum = temp32new; // Save latest accumulator away for next time
+ tempreg=(UINT16)(temp32>>12); // Select lower 16 of 20 bits
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.act_cnt=(UINT16)tempreg;
+ sensor_update(AMECSENSOR_PORTPAIR_PTR(mac2ms,i_centaur,i_mc_id), tempreg);
+
+ // --------------------------------------------------------------------------
+ // Sensor: MTS2MS (count) Last received Timestamp (frame count) from Centaur
+ // --------------------------------------------------------------------------
+ // Extract framecount (clock is 266.6666666MHz * 0.032 / 4096)=2083.
+ temp32new = l_sensor_cache->scache.frame_count;
+
+ // For DD1.0, we only have 1 channel field that we use; DD2.0 we need to add another channel
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.fr2_cnt_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.fr2_cnt_accum = temp32new; // Save latest accumulator away for next time
+ tempreg=(UINT16)(temp32>>12); // Select upper 20 bits
+
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.fr2_cnt=(UINT16)tempreg;
+ sensor_update(AMECSENSOR_PORTPAIR_PTR(mts2ms,i_centaur,i_mc_id), tempreg);
+
+ if (i_mc_id == 0)
+ {
+ tempu = l_sensor_cache->scache.mba01_cache_hits_rd;
+ templ = l_sensor_cache->scache.mba01_cache_hits_wr;
+ }
+ else
+ {
+ tempu = l_sensor_cache->scache.mba23_cache_hits_rd;
+ templ = l_sensor_cache->scache.mba23_cache_hits_wr;
+ }
+ // ----------------------------------------------------------------------
+ // Sensor: M4RD2MS (0.01 Mrps) Memory cached (L4) read requests per sec
+ // ----------------------------------------------------------------------
+ temp32new = (tempu); // left shift into top 20 bits of 32 bits
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.l4_rd_cnt_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.l4_rd_cnt_accum = temp32new; // Save latest accumulator away for next time
+
+ // Read every 2 ms....to convert to 0.01 Mrps = ((2ms read * 500)/10000)
+ tempreg = ((temp32*5)/100);
+ tempreg2 = g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.memread2ms;
+ // Firmware workaround for hardware bug: hits - memreads ~= hits
+ tempreg = tempreg - tempreg2;
+ // Deal with maintenance commands or quantization in counters being off by 12 and force to 0
+ if ((tempreg > 32767) || (tempreg <= 12))
+ {
+ tempreg=0;
+ }
+
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.l4rd2ms = tempreg;
+ sensor_update(AMECSENSOR_PORTPAIR_PTR(m4rd2ms,i_centaur,i_mc_id), tempreg);
+
+ // -----------------------------------------------------------------------
+ // Sensor: M4WR2MS (0.01 Mrps) Memory cached (L4) write requests per sec
+ // -----------------------------------------------------------------------
+ temp32new = (templ); // left shift into top 20 bits of 32 bits
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.l4_wr_cnt_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.l4_wr_cnt_accum = temp32new; // Save latest accumulator away for next time
+
+ // Read every 2 ms....to convert to 0.01 Mrps = ((2ms read * 500)/10000)
+ tempreg = ((temp32*5)/100);
+
+ tempreg2 = g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.memwrite2ms;
+ // Firmware workaround for hardware bug: hits - memwrites ~= hits
+ tempreg = tempreg - tempreg2;
+ // Deal with maintenance commands or quantization in counters being off by 12 and force to 0
+ if ((tempreg > 32767) || (tempreg <= 12))
+ {
+ tempreg=0;
+ }
+
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.l4wr2ms = tempreg;
+ sensor_update(AMECSENSOR_PORTPAIR_PTR(m4wr2ms,i_centaur,i_mc_id), tempreg);
+
+ // ------------------------------------------------------------------------------
+ // Sensor: MIRB2MS (0.01 Mevents/s) Memory Inter-request arrival idle intervals
+ // ------------------------------------------------------------------------------
+ temp32new = (i_mc_id == 0) ? l_sensor_cache->scache.mba01_intreq_arr_cnt_base : l_sensor_cache->scache.mba23_intreq_arr_cnt_base;
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.intreq_base_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.intreq_base_accum = temp32new; // Save latest accumulator away for next time
+
+ // Read every 2 ms....to convert to 0.01 Mrps = ((2ms read * 500)/10000)
+ tempreg = ((temp32*5)/100);
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.mirb2ms = tempreg;
+ sensor_update(AMECSENSOR_PORTPAIR_PTR(mirb2ms,i_centaur,i_mc_id), tempreg);
+
+ // --------------------------------------------------------------------------------------------------------
+ // Sensor: MIRL2MS (0.01 Mevents/s) Memory Inter-request arrival idle intervals longer than low threshold
+ // --------------------------------------------------------------------------------------------------------
+ temp32new = (i_mc_id == 0) ? l_sensor_cache->scache.mba01_intreq_arr_cnt_low : l_sensor_cache->scache.mba23_intreq_arr_cnt_low;
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.intreq_low_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.intreq_low_accum = temp32new; // Save latest accumulator away for next time
+
+ // Read every 2 ms....to convert to 0.01 Mrps = ((2ms read * 500)/10000)
+ tempreg = ((temp32*5)/100);
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.mirl2ms = tempreg;
+ sensor_update(AMECSENSOR_PORTPAIR_PTR(mirl2ms,i_centaur,i_mc_id), tempreg);
+
+ // -----------------------------------------------------------------------------------------------------------
+ // Sensor: MIRM2MS (0.01 Mevents/s) Memory Inter-request arrival idle intervals longer than medium threshold
+ // -----------------------------------------------------------------------------------------------------------
+ temp32new = (i_mc_id == 0) ? l_sensor_cache->scache.mba01_intreq_arr_cnt_med : l_sensor_cache->scache.mba23_intreq_arr_cnt_med;
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.intreq_med_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.intreq_med_accum = temp32new; // Save latest accumulator away for next time
+
+ // Read every 2 ms....to convert to 0.01 Mrps = ((2ms read * 500)/10000)
+ tempreg = ((temp32*5)/100);
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.mirm2ms = tempreg;
+ sensor_update(AMECSENSOR_PORTPAIR_PTR(mirm2ms,i_centaur,i_mc_id), tempreg);
+
+ // ---------------------------------------------------------------------------------------------------------
+ // Sensor: MIRH2MS (0.01 Mevents/s) Memory Inter-request arrival idle intervals longer than high threshold
+ // ---------------------------------------------------------------------------------------------------------
+ temp32new = (i_mc_id == 0) ? l_sensor_cache->scache.mba01_intreq_arr_cnt_high : l_sensor_cache->scache.mba23_intreq_arr_cnt_high;
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.intreq_high_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.intreq_high_accum = temp32new; // Save latest accumulator away for next time
+
+ // Read every 2 ms....to convert to 0.01 Mrps = ((2ms read * 500)/10000)
+ tempreg = ((temp32*5)/100);
+ g_amec->proc[0].memctl[i_centaur].centaur.portpair[i_mc_id].perf.mirh2ms = tempreg;
+ sensor_update(AMECSENSOR_PORTPAIR_PTR(mirh2ms,i_centaur,i_mc_id), tempreg);
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ // Sensor: MIRC2MS (0.01 Mevents/s) Memory Inter-request arrival idle interval longer than programmed threshold
+ // --------------------------------------------------------------------------------------------------------------
+ temp32new = l_sensor_cache->scache.intreq_arr_cnt_high_latency;
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.perf.intreq_highlatency_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.perf.intreq_highlatency_accum = temp32new; // Save latest accumulator away for next time
+
+ // Read every 2 ms....to convert to 0.01 Mrps = ((2ms read * 500)/10000)
+ tempreg = ((temp32*5)/100);
+ g_amec->proc[0].memctl[i_centaur].centaur.perf.mirc2ms = tempreg;
+ sensor_update((&(g_amec->proc[0].memctl[i_centaur].centaur.mirc2ms)), tempreg);
+
+ // ----------------------------------------------------
+ // Sensor: MLP2MS (events/s) Number of LP2 exits
+ // ----------------------------------------------------
+ temp32new = l_sensor_cache->scache.lp2_exits;
+ temp32 = temp32new - g_amec->proc[0].memctl[i_centaur].centaur.perf.lp2exit_accum;
+ g_amec->proc[0].memctl[i_centaur].centaur.perf.lp2exit_accum = temp32new; // Save latest accumulator away for next time
+
+ // Read every 2 ms....to convert to 0.01 Mrps = ((2ms read * 500)/10000)
+ tempreg = ((temp32*5)/100);
+ g_amec->proc[0].memctl[i_centaur].centaur.perf.mlp2_2ms = tempreg;
+ sensor_update((&(g_amec->proc[0].memctl[i_centaur].centaur.mlp2ms)), tempreg);
+
+ // ------------------------------------------------------------
+ // Sensor: MRD2MSP0Mx (0.01 Mrps) Memory read requests per sec
+ // ------------------------------------------------------------
+ tempreg = g_amec->proc[0].memctl[i_centaur].centaur.portpair[0].perf.memread2ms;
+ tempreg += g_amec->proc[0].memctl[i_centaur].centaur.portpair[1].perf.memread2ms;
+ sensor_update( (&(g_amec->proc[0].memctl[i_centaur].mrd2ms)), tempreg);
+
+ // -------------------------------------------------------------
+ // Sensor: MWR2MSP0Mx (0.01 Mrps) Memory write requests per sec
+ // -------------------------------------------------------------
+ tempreg = g_amec->proc[0].memctl[i_centaur].centaur.portpair[0].perf.memwrite2ms;
+ tempreg += g_amec->proc[0].memctl[i_centaur].centaur.portpair[1].perf.memwrite2ms;
+ sensor_update( (&(g_amec->proc[0].memctl[i_centaur].mwr2ms)), tempreg);
+
+ return;
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_sensors_centaur.h b/src/occ_405/amec/amec_sensors_centaur.h
new file mode 100644
index 0000000..ddc3132
--- /dev/null
+++ b/src/occ_405/amec/amec_sensors_centaur.h
@@ -0,0 +1,36 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_sensors_centaur.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 _AMEC_SENSORS_CENTAUR_H
+#define _AMEC_SENSORS_CENTAUR_H
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+void amec_update_centaur_sensors(uint8_t i_centaur);
+void amec_update_centaur_temp_sensors(void);
+
+#endif
+
diff --git a/src/occ_405/amec/amec_sensors_core.c b/src/occ_405/amec/amec_sensors_core.c
new file mode 100755
index 0000000..bdea518
--- /dev/null
+++ b/src/occ_405/amec/amec_sensors_core.c
@@ -0,0 +1,882 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_sensors_core.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 */
+
+/******************************************************************************/
+/* Includes */
+/******************************************************************************/
+#include <occ_common.h>
+#include <ssx.h>
+#include <errl.h> // Error logging
+#include "sensor.h"
+#include "rtls.h"
+#include "occ_sys_config.h"
+#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE
+#include "dcom.h"
+#include "proc_data.h"
+#include "amec_smh.h"
+#include "amec_slave_smh.h"
+#include <trac.h>
+#include "amec_sys.h"
+#include "sensor_enum.h"
+#include "amec_service_codes.h"
+#include <amec_sensors_core.h>
+#include "amec_perfcount.h"
+
+/******************************************************************************/
+/* Globals */
+/******************************************************************************/
+
+/******************************************************************************/
+/* Forward Declarations */
+/******************************************************************************/
+void amec_calc_dts_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core);
+//void amec_calc_cpm_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core); //CPM - Commented out as requested by Malcolm
+void amec_calc_freq_and_util_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core);
+void amec_calc_ips_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core);
+void amec_calc_spurr(uint8_t i_core);
+
+//*************************************************************************
+// Code
+//*************************************************************************
+
+// Function Specification
+//
+// Name: amec_update_fast_core_data_sensors
+//
+// Description: Updates sensors that have data grabbed by the fast core data
+// task.
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_update_fast_core_data_sensors(void)
+{
+ // ------------------------------------------------------
+ // Update Fast Core Data Sensors
+ // ------------------------------------------------------
+ // SensorNameCx = PCBS Local Pstate Freq Target (per core)
+ // TODclock = TOD Clock?
+
+ // Need to comment this out because l_tod is always zero, which messes
+ // up proper sensor updates. Proper updating is done below in the core level
+ // sensor updates.
+
+ //gpe_fast_core_data_t * l_core = proc_get_fast_core_data_ptr();
+ // uint32_t l_tod = l_core->tod;
+
+ //if( l_core != NULL)
+ //{
+ // GPEtickdur0 = duration of last tick's PORE-GPE0 duration
+ // sensor_update( AMECSENSOR_PTR(TODclock0), CONVERT_UINT32_UINT8_UPPER_HIGH(l_tod) );
+ // sensor_update( AMECSENSOR_PTR(TODclock1), CONVERT_UINT32_UINT16_MIDDLE(l_tod) );
+ // sensor_update( AMECSENSOR_PTR(TODclock2), ((uint16_t) (CONVERT_UINT32_UINT8_LOWER_LOW(l_tod))) << 8);
+ //}
+
+ // TODO: Don't know what to update from the PCBS LPstate Target Freq Status Reg
+ //for(int i=0; i++; i<MAX_NUM_HW_CORES)
+ //{
+ // sensor_update(&sensor,
+ // G_read_fast_core_data_ptr->core_data[i].pcbs_lpstate_freq_target_sr);
+ //}
+}
+
+
+// Function Specification
+//
+// Name: amec_update_proc_core_sensors
+//
+// Description: Update all the sensors for a given proc
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_update_proc_core_sensors(uint8_t i_core)
+{
+ gpe_bulk_core_data_t * l_core_data_ptr;
+ int i;
+ uint16_t l_temp16 = 0;
+ uint32_t l_temp32 = 0;
+
+ // Make sure the core is present, and that it has updated data.
+ if(CORE_PRESENT(i_core) && CORE_UPDATED(i_core))
+ {
+ // Clear flag indicating core was updated by proc task
+ CLEAR_CORE_UPDATED(i_core);
+
+ // Get pointer to core data
+ l_core_data_ptr = proc_get_bulk_core_data_ptr(i_core);
+
+ //-------------------------------------------------------
+ // Thermal Sensors & Calc
+ //-------------------------------------------------------
+ amec_calc_dts_sensors(l_core_data_ptr, i_core);
+
+ //-------------------------------------------------------
+ //CPM - Commented out as requested by Malcolm
+ // ------------------------------------------------------
+ // amec_calc_cpm_sensors(l_core_data_ptr, i_core);
+
+ //-------------------------------------------------------
+ // Util / Freq
+ //-------------------------------------------------------
+ // Skip this update if there was an empath collection error
+ if (!CORE_EMPATH_ERROR(i_core))
+ {
+ amec_calc_freq_and_util_sensors(l_core_data_ptr,i_core);
+ }
+
+ //-------------------------------------------------------
+ // Performance counter - This function should be called
+ // after amec_calc_freq_and_util_sensors().
+ //-------------------------------------------------------
+ amec_calc_dps_util_counters(i_core);
+
+ //-------------------------------------------------------
+ // IPS
+ //-------------------------------------------------------
+ // Skip this update if there was an empath collection error
+ if (!CORE_EMPATH_ERROR(i_core))
+ {
+ amec_calc_ips_sensors(l_core_data_ptr,i_core);
+ }
+
+ //-------------------------------------------------------
+ // SPURR
+ //-------------------------------------------------------
+ amec_calc_spurr(i_core);
+
+ // ------------------------------------------------------
+ // Update PREVIOUS values for next time
+ // ------------------------------------------------------
+ g_amec->proc[0].core[i_core].prev_PC_RAW_Th_CYCLES = l_core_data_ptr->per_thread[0].raw_cycles;
+
+ // Skip empath updates if there was an empath collection error on this core
+ if (!CORE_EMPATH_ERROR(i_core))
+ {
+ g_amec->proc[0].core[i_core].prev_PC_RAW_CYCLES = l_core_data_ptr->empath.raw_cycles;
+ g_amec->proc[0].core[i_core].prev_PC_RUN_CYCLES = l_core_data_ptr->empath.run_cycles;
+ g_amec->proc[0].core[i_core].prev_PC_COMPLETED = l_core_data_ptr->empath.completion;
+ g_amec->proc[0].core[i_core].prev_PC_DISPATCH = l_core_data_ptr->empath.dispatch;
+ g_amec->proc[0].core[i_core].prev_tod_2mhz = l_core_data_ptr->empath.tod_2mhz;
+ g_amec->proc[0].core[i_core].prev_FREQ_SENS_BUSY = l_core_data_ptr->empath.freq_sens_busy;
+ g_amec->proc[0].core[i_core].prev_FREQ_SENS_FINISH = l_core_data_ptr->empath.freq_sens_finish;
+ }
+
+ for(i=0; i<MAX_THREADS_PER_CORE; i++)
+ {
+ g_amec->proc[0].core[i_core].thread[i].prev_PC_RUN_Th_CYCLES = l_core_data_ptr->per_thread[i].run_cycles;
+ }
+
+ // Final step is to update TOD sensors
+ // Extract 32 bits with 16usec resolution
+ l_temp32 = (uint32_t)(G_dcom_slv_inbox_doorbell_rx.tod>>13);
+ l_temp16 = (uint16_t)(l_temp32);
+ // low 16 bits is 16usec resolution with 512MHz TOD clock
+ sensor_update( AMECSENSOR_PTR(TODclock0), l_temp16);
+ l_temp16 = (uint16_t)(l_temp32>>16);
+ // mid 16 bits is 1.05sec resolution with 512MHz TOD clock
+ sensor_update( AMECSENSOR_PTR(TODclock1), l_temp16);
+ l_temp16 = (uint16_t)(G_dcom_slv_inbox_doorbell_rx.tod>>45);
+ // hi 3 bits in 0.796 day resolution with 512MHz TOD clock
+ sensor_update( AMECSENSOR_PTR(TODclock2), l_temp16);
+ }
+}
+
+
+// Function Specification
+//
+// Name: amec_calc_dts_sensors
+//
+// Description: Compute core temperature. This function is called every
+// 2ms/core.
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_calc_dts_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core)
+{
+#define DTS_PER_CORE 4
+#define DTS_INVALID_MASK 0x0C00
+
+ uint32_t k, l_core_avg, l_core_hot, l_sensor_count;
+ uint32_t l_oha_status_reg = 0;
+ uint32_t l_pm_state_hist_reg = 0;
+ uint16_t l_dts[DTS_PER_CORE];
+ BOOLEAN l_update_sensor = FALSE;
+
+ // Build up array of DTS values
+ // DTS sensors are in the format of uint64_t dts0 : 12;
+ // uint64_t thermal_trip0 : 2;
+ // uint64_t spare0 : 1;
+ // uint64_t valid0 : 1;
+ //
+ // so we will need to convert them before they are used in loop below.
+ l_dts[0] = i_core_data_ptr->dts_cpm.sensors_v0.fields.dts0;
+ l_dts[1] = i_core_data_ptr->dts_cpm.sensors_v0.fields.dts1;
+ l_dts[2] = i_core_data_ptr->dts_cpm.sensors_v0.fields.dts2;
+ l_dts[3] = i_core_data_ptr->dts_cpm.sensors_v1.fields.dts4;
+
+ // Read the low-order bytes of the OHA Status register
+ l_oha_status_reg = i_core_data_ptr->oha.oha_ro_status_reg.words.low_order;
+
+ // Read the high-order bytes of PM State History register for this core
+ l_pm_state_hist_reg = i_core_data_ptr->pcb_slave.pm_history.words.high_order;
+
+ // Check if we were able to collect core data
+ if(l_oha_status_reg & CORE_DATA_CORE_SENSORS_COLLECTED)
+ {
+ // Check if all DTS readings in the core are valid. The field sensors_v0
+ // contains core-related data
+ if(i_core_data_ptr->dts_cpm.sensors_v0.fields.valid0 ||
+ i_core_data_ptr->dts_cpm.sensors_v0.fields.valid1 ||
+ i_core_data_ptr->dts_cpm.sensors_v0.fields.valid2)
+ {
+ l_update_sensor = TRUE;
+ }
+ }
+ // Check if we were able to collect L3 data
+ if(l_oha_status_reg & CORE_DATA_L3_SENSORS_COLLECTED)
+ {
+ // Check if DTS reading in the L3 is valid. The field sensors_v1 contains
+ // L3-related data
+ if(i_core_data_ptr->dts_cpm.sensors_v1.fields.valid4)
+ {
+ l_update_sensor = TRUE;
+ }
+ }
+ // Check if this core has been in fast winkle OR deep winkle
+ if(((l_pm_state_hist_reg & OCC_PM_STATE_MASK) == OCC_PAST_FAST_WINKLE) ||
+ ((l_pm_state_hist_reg & OCC_PM_STATE_MASK) == OCC_PAST_DEEP_WINKLE))
+ {
+ l_update_sensor = TRUE;
+ }
+
+ // Update the thermal sensor associated with this core
+ if(l_update_sensor)
+ {
+ //calculate average temperature from all DTS's for this core
+ for(l_sensor_count = DTS_PER_CORE, l_core_hot = 0,
+ l_core_avg = 0, k = 0;
+ k < DTS_PER_CORE; k++)
+ {
+ //Hardware bug workaround: Temperatures reaching 0 degrees C
+ //can show up as negative numbers. To fix this, we discount
+ //values that have the 2 MSB's set.
+ if((l_dts[k] & DTS_INVALID_MASK) == DTS_INVALID_MASK)
+ {
+ l_dts[k] = 0;
+ }
+
+ l_core_avg += l_dts[k];
+ if(l_dts[k] > l_core_hot)
+ {
+ l_core_hot = l_dts[k];
+ }
+ // Assume 0 degrees to mean bad sensor and don't let it bring the
+ // average reading down.
+ else if(l_dts[k] == 0)
+ {
+ l_sensor_count--;
+ }
+ }
+
+ if(l_sensor_count == DTS_PER_CORE)
+ {
+ //For the common case, compiler converts this to a fast multiplication
+ //operation when one of the operands is a constant.
+ l_core_avg /= DTS_PER_CORE;
+ }
+ else if(l_sensor_count) //prevent div by 0 if all sensors are zero
+ {
+ //otherwise, use the slower division routine when both operands are
+ //unknown at compile time.
+ l_core_avg /= l_sensor_count;
+ }
+
+ // Update sensors & Interim Data
+ sensor_update( AMECSENSOR_ARRAY_PTR(TEMP2MSP0C0,i_core), l_core_avg);
+ g_amec->proc[0].core[i_core].dts_hottest = l_core_hot;
+ }
+}
+
+
+//CPM - Commented out as requested by Malcolm
+/* void amec_calc_cpm_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core)
+{
+#define CPM_PER_CORE 4
+
+ uint32_t k, l_cpm_min = 0xffffffff;
+ uint16_t l_cpm[CPM_PER_CORE];
+
+ l_cpm[0] = i_core_data_ptr->dts_cpm.sensors_v8.fields.encoded_cpm0;
+ l_cpm[1] = i_core_data_ptr->dts_cpm.sensors_v8.fields.encoded_cpm1;
+ l_cpm[2] = i_core_data_ptr->dts_cpm.sensors_v8.fields.encoded_cpm2;
+ l_cpm[3] = i_core_data_ptr->dts_cpm.sensors_v9.fields.encoded_cpm4;
+
+ //calculate min CPM from all CPM's for this core
+ for(k = 0; k < CPM_PER_CORE; k++)
+ {
+ if(l_cpm[k] < l_cpm_min)
+ {
+ l_cpm_min = l_cpm[k];
+ }
+ }
+
+ sensor_update( AMECSENSOR_ARRAY_PTR(CPM2MSP0C0,i_core), l_cpm_min);
+}
+*/
+
+// Function Specification
+//
+// Name: amec_calc_freq_and_util_sensors
+//
+// Description: Compute the frequency and utilization sensors for a given core.
+// This function is called every 2ms/core.
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_calc_freq_and_util_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core)
+{
+ BOOLEAN l_core_sleep_winkle = FALSE;
+ uint32_t l_pm_state_hist_reg = 0;
+ uint32_t temp32 = 0;
+ uint32_t temp32a = 0;
+ uint16_t temp16 = 0;
+ uint16_t temp16a = 0;
+ uint16_t l_core_util = 0;
+ uint16_t l_core_freq = 0;
+ uint16_t l_time_interval = 0;
+ uint32_t l_cycles2ms = 0;
+ int i;
+
+ // Read the high-order bytes of PM State History register for this core
+ l_pm_state_hist_reg = i_core_data_ptr->pcb_slave.pm_history.words.high_order;
+
+ // If core is in fast/deep sleep mode or fast/winkle mode, then set a flag
+ // indicating this
+ if(l_pm_state_hist_reg & OCC_PAST_CORE_CLK_STOP)
+ {
+ l_core_sleep_winkle = TRUE;
+ }
+
+ // ------------------------------------------------------
+ // Per Core Frequency
+ // ------------------------------------------------------
+ // <amec_formula>
+ // Result: Calculated Core Frequency
+ // Sensor: FREQA2MSP0C0
+ // Timescale: 2ms
+ // Units: MHz
+ // Min/Max: 0/6000 (UPPER_LIMIT_PROC_FREQ_MHZ=6000)
+ // Formula: cyc_delta = (RAW_CYCLES[t=now] - RAW_CYCLES[t=-2ms])
+ // time_delta = (TOD[t=now] - TOD[t=-2ms])
+ // frequency(MHz) = (cyc_delta / time_delta) * (2M TOD ticks / 1 second)
+ // = (2 * cyc_delta) / time_delta
+ // </amec_formula>
+
+ // Compute Delta in PC_RAW_CYCLES
+ temp32 = i_core_data_ptr->empath.raw_cycles;
+ temp32a = g_amec->proc[0].core[i_core].prev_PC_RAW_CYCLES;
+ temp32 = l_cycles2ms = temp32 - temp32a;
+
+ if( (cfam_id() == CFAM_CHIP_ID_MURANO_10)
+ || (cfam_id() == CFAM_CHIP_ID_MURANO_11)
+ || (cfam_id() == CFAM_CHIP_ID_MURANO_12) )
+ {
+ temp32a = AMEC_US_PER_SMH_PERIOD; // using fixed 2000us is showing 3% error.
+ temp32 = temp32 / temp32a;
+ }
+ else
+ {
+ temp32a = (i_core_data_ptr->empath.tod_2mhz -
+ g_amec->proc[0].core[i_core].prev_tod_2mhz);
+ temp32 = (2 * temp32) / temp32a;
+ }
+
+ // TODO: Remove this once we have the OHA Power Proxy legacy mode stuff working.
+ if(temp32 < UPPER_LIMIT_PROC_FREQ_MHZ)
+ {
+ // Update Sensor for this core
+ if(l_core_sleep_winkle)
+ {
+ l_core_freq = 0;
+ }
+ else
+ {
+ l_core_freq = (uint16_t) temp32;
+ }
+ sensor_update( AMECSENSOR_ARRAY_PTR(FREQA2MSP0C0,i_core), l_core_freq);
+ }
+
+ // ------------------------------------------------------
+ // Per Core Utilization
+ // ------------------------------------------------------
+ // <amec_formula>
+ // Result: Calculated Core Utilization
+ // Sensor: UTIL2MSP0C0
+ // Timescale: 2ms
+ // Units: 0.01 %
+ // Min/Max: 0/10000 (0/100%)
+ // Formula: cyc_delta = (RAW_CYCLES[t=now] - RAW_CYCLES[t=-2ms])
+ // run_delta = (RUN_CYCLES[t=now] - RUN_CYCLES[t=-2ms])
+ //
+ // UTIL(in %) = run_delta / cyc_delta
+ // </amec_formula>
+
+ // Compute Delta in PC_RUN_CYCLES
+ temp32 = i_core_data_ptr->empath.run_cycles;
+ temp32a = g_amec->proc[0].core[i_core].prev_PC_RUN_CYCLES;
+ temp32 = temp32 - temp32a;
+
+ temp32 = temp32 >> 8; // Drop non-significant bits
+ temp16 = (uint16_t) temp32; // Cast to uint16 for mult below
+ temp16a = 10000; // Mult * 10000 to get finer resolution for 0.01%
+ temp32 = ((uint32_t)temp16a)*((uint32_t)temp16);
+
+ temp32a = l_cycles2ms; // Get Raw cycles
+ temp32a = temp32a >> 8; // Drop non-significant bits
+
+ // Calculate Utilization
+ temp32 = temp32 / temp32a;
+ if(temp32a == 0) // Prevent a divide by zero
+ {
+ temp32 = 0;
+ }
+
+ // Update Sensor for this core
+ if(l_core_sleep_winkle)
+ {
+ l_core_util = 0;
+ }
+ else
+ {
+ l_core_util = (uint16_t) temp32;
+ }
+ sensor_update(AMECSENSOR_ARRAY_PTR(UTIL2MSP0C0, i_core), l_core_util);
+
+
+ // ------------------------------------------------------
+ // Per Thread Utilization
+ // ------------------------------------------------------
+ // <amec_formula>
+ // Result: Calculated Core Utilization
+ // Sensor: None
+ // Timescale: 2ms
+ // Units: 0.01 %
+ // Min/Max: 0/10000 (0/100%)
+ // Formula: cyc_delta = (RAW_CYCLES[t=now] - RAW_CYCLES[t=-2ms])
+ // run_delta = (RUN_CYCLES[t=now] - RUN_CYCLES[t=-2ms])
+ //
+ // UTIL(in %) = run_delta / cyc_delta
+ // </amec_formula>
+
+ // Get RAW CYCLES for Thread
+ temp32 = i_core_data_ptr->per_thread[0].raw_cycles;
+ temp32a = g_amec->proc[0].core[i_core].prev_PC_RAW_Th_CYCLES;
+ temp32 = l_cycles2ms = temp32 - temp32a;
+
+ for(i=0; i<MAX_THREADS_PER_CORE; i++)
+ {
+ // Get Run Counters for Thread
+ temp32 = i_core_data_ptr->per_thread[i].run_cycles;
+ temp32a = g_amec->proc[0].core[i_core].thread[i].prev_PC_RUN_Th_CYCLES;
+ temp32 = temp32 - temp32a;
+
+ temp32 = temp32 >> 8; // Drop non-significant bits
+ temp16 = (uint16_t) temp32; // Cast to uint16 for mult below
+ temp16a = 10000; // Mult * 10000 to get finer resolution for 0.01%
+ temp32 = ((uint32_t)temp16a)*((uint32_t)temp16);
+
+ temp32a = l_cycles2ms;
+ temp32a = temp32a >> 8; // Drop non-significant bits
+
+ // Calculate Utilization
+ temp32 = temp32 / temp32a;
+
+ // Update per thread value for this core
+ if(l_core_sleep_winkle)
+ {
+ temp32 = 0;
+ }
+ g_amec->proc[0].core[i_core].thread[i].util2ms_thread = (uint16_t) temp32;
+ }
+
+ // No sensors to update for perThread Util
+
+ // ------------------------------------------------------
+ // Per Core Sleep/Winkle Count
+ // ------------------------------------------------------
+
+ // Get Current Idle State of Chiplet
+ // The SLEEPCNT and WINKLECNT sensors are updated in amec_slv_state_0() function
+ temp16 = CONVERT_UINT64_UINT16_UPPER(i_core_data_ptr->pcb_slave.pm_history.value);
+ temp16 = temp16 & 0xE000;
+ temp16 = temp16 >> 13;
+ switch(temp16)
+ {
+ case 0: break; // Run State
+ case 1: break; // Special Wakeup
+ case 2: break; // Nap
+ case 3: SETBIT(g_amec->proc[0].sleep_cnt,i_core); break; // Legacy Sleep
+ case 4: SETBIT(g_amec->proc[0].sleep_cnt,i_core); break; // Fast Sleep
+ case 5: SETBIT(g_amec->proc[0].sleep_cnt,i_core); break; // Deep Sleep
+ case 6: SETBIT(g_amec->proc[0].winkle_cnt,i_core); break; // Fast Winkle
+ case 7: SETBIT(g_amec->proc[0].winkle_cnt,i_core); break; // Deep Winkle
+ }
+
+ // ------------------------------------------------------
+ // Core Memory Hierarchy C LPARx Utilization counters
+ // ------------------------------------------------------
+ for(i=0; i<4; i++)
+ {
+ // Extract the utilization counter
+ temp32 = i_core_data_ptr->per_partition_memory.count[i];
+
+ // Convert counter to 0.01 Mrps resolution. Since we access every 2 ms:
+ // ((2ms read * 500) / 10000)
+ temp32a = temp32 - g_amec->proc[0].core[i_core].prev_lpar_mem_cnt[i];
+ g_amec->proc[0].core[i_core].prev_lpar_mem_cnt[i] = temp32;
+ temp32 = (temp32a * 5) / 100;
+
+ // Store the bandwidth for this LPAR
+ g_amec->proc[0].core[i_core].membw[i] = (uint16_t)temp32;
+ }
+
+ // Sum up all the memory bandwidth data from the LPARs
+ temp32 = g_amec->proc[0].core[i_core].membw[0] +
+ g_amec->proc[0].core[i_core].membw[1] +
+ g_amec->proc[0].core[i_core].membw[2] +
+ g_amec->proc[0].core[i_core].membw[3];
+
+ // Divide by two due to a bug in the hardware
+ temp32 = temp32/2;
+
+ // See if core is sleeping/winkled
+ if(l_core_sleep_winkle)
+ {
+ temp32 = 0;
+ }
+ // Update Sensor for this core
+ sensor_update( AMECSENSOR_ARRAY_PTR(CMBW2MSP0C0,i_core), (uint16_t) temp32);
+
+ // ------------------------------------------------------
+ // Core Stall counters
+ // ------------------------------------------------------
+ temp32 = i_core_data_ptr->empath.freq_sens_busy;
+ temp32a = g_amec->proc[0].core[i_core].prev_FREQ_SENS_BUSY;
+ temp32 = temp32 - temp32a;
+ temp32 = temp32 >> 8;
+
+ // See if core is sleeping/winkled
+ if(l_core_sleep_winkle)
+ {
+ temp32 = 0;
+ }
+
+ // Update Sensor for this core
+ sensor_update( AMECSENSOR_ARRAY_PTR(NOTBZE2MSP0C0,i_core), (uint16_t) temp32);
+
+ temp32 = i_core_data_ptr->empath.freq_sens_finish;
+ temp32a = g_amec->proc[0].core[i_core].prev_FREQ_SENS_FINISH;
+ temp32 = temp32 - temp32a;
+ temp32 = temp32 >> 8;
+
+ // See if core is sleeping/winkled
+ if(l_core_sleep_winkle)
+ {
+ temp32 = 0;
+ }
+
+ // Update Sensor for this core
+ sensor_update( AMECSENSOR_ARRAY_PTR(NOTFIN2MSP0C0,i_core), (uint16_t) temp32);
+
+ // ------------------------------------------------------
+ // Per Core Normalized Average Utilization
+ // ------------------------------------------------------
+ // <amec_formula>
+ // Result: Calculated Normalized Average Core Utilization
+ // Sensor: NUTIL3SP0C0
+ // Timescale: 2ms (3s rolling average)
+ // Units: 0.01 %
+ // Min/Max: 0/10000 (0/100%)
+ // </amec_formula>
+
+ // Determine the time interval for the rolling average calculation
+ l_time_interval = AMEC_DPS_SAMPLING_RATE * AMEC_IPS_AVRG_INTERVAL;
+
+ // Increment our sample count but prevent it from wrapping
+ if(g_amec->proc[0].core[i_core].sample_count < UINT16_MAX)
+ {
+ g_amec->proc[0].core[i_core].sample_count++;
+ }
+
+ if(g_amec->proc[0].core[i_core].sample_count == l_time_interval)
+ {
+ // Increase resolution of the UTIL accumulator by two decimal places
+ temp32 = AMECSENSOR_ARRAY_PTR(UTIL2MSP0C0,i_core)->accumulator * 100;
+ // Calculate average utilization of this core
+ temp32 = temp32 / g_amec->proc[0].core[i_core].sample_count;
+ g_amec->proc[0].core[i_core].avg_util = temp32;
+
+ // Increase resolution of the FREQA accumulator by two decimal places
+ temp32 = AMECSENSOR_ARRAY_PTR(FREQA2MSP0C0,i_core)->accumulator * 100;
+ // Calculate average frequency of this core
+ temp32 = temp32 / g_amec->proc[0].core[i_core].sample_count;
+ g_amec->proc[0].core[i_core].avg_freq = temp32;
+ }
+
+ if(g_amec->proc[0].core[i_core].sample_count > l_time_interval)
+ {
+ // Calculate average utilization for this core
+ temp32 = (uint32_t) g_amec->proc[0].core[i_core].avg_util;
+ temp32 = temp32 * (l_time_interval-1);
+ temp32 = temp32 + l_core_util*100;
+ g_amec->proc[0].core[i_core].avg_util = temp32 / l_time_interval;
+
+ // Could be needed for increase accuracy
+ //if(g_amec->proc[0].core[i_core].avg_util > 9000)
+ //{ This rounds up only!
+ //g_amec->proc[0].core[i_core].avg_util = (temp32+ (1500-1)) / 1500;
+ //}
+
+ // Calculate average frequency for this core
+ temp32 = (uint32_t) g_amec->proc[0].core[i_core].avg_freq;
+ temp32 = temp32 * (l_time_interval-1);
+ temp32 = temp32 + l_core_freq*100;
+ g_amec->proc[0].core[i_core].avg_freq = temp32 / l_time_interval;
+ }
+
+ // Calculate the normalized utilization for this core
+ if(g_amec->proc[0].core[i_core].avg_freq != 0)
+ {
+ // First, revert back to the original resolution of the sensors
+ temp32 = g_amec->proc[0].core[i_core].avg_util / 100;
+ temp32a = g_amec->proc[0].core[i_core].avg_freq / 100;
+
+ // Compute now the normalized utilization as follows:
+ // Normalized utilization = (Average_utilization)/(Average_frequency) * Fnom
+ // Note: The 100000 constant is to increase the precision of our division
+ temp32 = (temp32 * 100000) / temp32a;
+ temp32 = (temp32 * G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL]) / 100000;
+
+ // Update sensor for this core
+ if(l_core_sleep_winkle)
+ {
+ sensor_update(AMECSENSOR_ARRAY_PTR(NUTIL3SP0C0, i_core), 0);
+ }
+ else
+ {
+ sensor_update(AMECSENSOR_ARRAY_PTR(NUTIL3SP0C0, i_core), (uint16_t)temp32);
+ }
+ }
+}
+
+
+void amec_calc_ips_sensors(gpe_bulk_core_data_t * i_core_data_ptr, uint8_t i_core)
+{
+#define TWO_PWR_24_MASK 0x00FFFFFF
+#define TWO_PWR_20_MASK 0x000FFFFF
+
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ INT32 cyc1 = 0; //cycle counts
+ INT32 cyc2 = 0;
+ UINT32 fin1 = 0; //finished instruction counts
+ UINT32 fin2 = 0;
+ INT32 disp1 = 0; //dispatched instruction counts
+ INT32 disp2 = 0;
+ UINT32 temp32 = 0;
+ UINT32 ticks_2mhz = 0; // IPS sensor interval in 2mhz ticks
+ BOOLEAN l_core_sleep_winkle = FALSE;
+ uint32_t l_pm_state_hist_reg = 0;
+
+
+ // Read the high-order bytes of PM State History register for this core
+ l_pm_state_hist_reg = i_core_data_ptr->pcb_slave.pm_history.words.high_order;
+
+ // If core is in fast/deep sleep mode or fast/winkle mode, then set a flag
+ // indicating this
+ if(l_pm_state_hist_reg & OCC_PAST_CORE_CLK_STOP)
+ {
+ l_core_sleep_winkle = TRUE;
+ }
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Get Run Cycles
+ cyc1 = i_core_data_ptr->empath.run_cycles;
+ cyc2 = g_amec->proc[0].core[i_core].prev_PC_RUN_CYCLES;
+ cyc2 = cyc1 - cyc2;
+
+ // Following lines look bogus...the counters are supposed to be 32-bit
+ // since we are doing 24-bit unsigned math, we need to account for the
+ // overflow case. If this occurs, we mask off the "overflow" to make it behave
+ // like a 32-bit subtraction overflow would. Commenting them out.
+ //if ( cyc2 < 0 )
+ //{
+ // cyc2 &= TWO_PWR_24_MASK;
+ //}
+
+ fin1 = i_core_data_ptr->empath.completion;
+ fin2 = g_amec->proc[0].core[i_core].prev_PC_COMPLETED;
+ fin2 = fin1 - fin2;
+
+ // Is this counting every completed instruction or 1 of every 16?
+ // Why are we masking 20 bits of a 32-bit counter? Commenting these lines out.
+ //if ( fin2 < 0 )
+ //{
+ // fin2 &= TWO_PWR_20_MASK;
+ //}
+
+ disp1 = i_core_data_ptr->empath.dispatch;
+ disp2 = g_amec->proc[0].core[i_core].prev_PC_DISPATCH;
+ disp2 = disp1 - disp2;
+
+ if ( disp2 < 0 )
+ {
+ disp2 &= TWO_PWR_20_MASK;
+ }
+
+ // ------------------------------------------------------
+ // Per Core IPC Calculation
+ // ------------------------------------------------------
+ // <amec_formula>
+ // Result: Calculated Instructions per Cycle
+ // Sensor: None
+ // Timescale: 2ms
+ // Units: 0.01 IPC
+ // Min/Max: ?
+ // Formula: ipc_delta = (INST_COMPLETE[t=now] - INST_COMPLETE[t=-2ms])
+ // run_cycles = (RUN_CYCLES[t=now] - RUN_CYCLES[t=-2ms])
+ // 100 = Convert 0.01 DPC
+ //
+ // IPC(in 0.01 IPC) = (ipc_delta * 100) / run_cycles
+ // </amec_formula>
+ temp32 = (fin2 * 100); // In units of IPS
+ temp32 = temp32 / cyc2; // In units of 0.01 DPC
+ g_amec->proc[0].core[i_core].ipc = temp32;
+
+
+ // ------------------------------------------------------
+ // Per Core DPC Calculation
+ // ------------------------------------------------------
+ // <amec_formula>
+ // Result: Calculated dispatched Instructions per Cycle
+ // Sensor: None
+ // Timescale: 2ms
+ // Units: 0.2Mips
+ // Min/Max: ?
+ // Formula: dpc_delta = (INST_DISPATCH[t=now] - INST_DISPATCH[t=-2ms])
+ // run_cycles = (RUN_CYCLES[t=now] - RUN_CYCLES[t=-2ms])
+ // 100 = Convert 0.01 DPC
+ //
+ // DPC(in 0.01DPC) = (dpc_delta * 100) / run_cycles
+ // </amec_formula>
+ temp32 = (disp2 * 100); // In units of IPS
+ temp32 = temp32 / cyc2; // In units of 0.01 DPC
+ g_amec->proc[0].core[i_core].dpc = temp32;
+
+ // ------------------------------------------------------
+ // Per Core DPS Calculation
+ // ------------------------------------------------------
+ // <amec_formula>
+ // Result: Calculated dispatched Instructions per Second
+ // Sensor: None
+ // Timescale: 2ms
+ // Units: 0.2Mips
+ // Min/Max: ?
+ // Formula: dps_delta = (INST_DISPATCH[t=now] - INST_DISPATCH[t=-2ms])
+ // 500 = # of 2ms periods in 1 second
+ // 50,000 = Convert IPS to 0.2MIPS
+ //
+ // DPS(in 0.2Mips) = (dps_delta * 500) / 50,000
+ // </amec_formula>
+ temp32 = (disp2 * AMEC_SMH_PERIODS_IN_1SEC); // In untis of IPS
+ temp32 = temp32 / 50000; // In units of 0.2Mips (max 327675 Mips for uint16_t)
+ g_amec->proc[0].core[i_core].dps = temp32;
+
+ // ------------------------------------------------------
+ // Per Core IPS Calculation
+ // ------------------------------------------------------
+ // <amec_formula>
+ // Result: Calculated Instructions per Second
+ // Sensor: IPS2MSP0C0
+ // Timescale: 2ms
+ // Units: 0.2Mips
+ // Min/Max: ?
+ // Formula:
+ // comp_delta = (INST_COMPLETE[t=now] - INST_COMPLETE[t=-2ms])
+ // ticks_delta = (TOD[t=now] - TOD[t=-2ms])
+ // MIPS = comp_delta (insns/interval) * (1 interval per ticks_delta 2mhz ticks) * (2M 2mhz ticks / s) / 1M
+ // = (2* fin2) / ticks_2mhz
+ // Note: For best resolution do multiply first and division last.
+ // </amec_formula>
+
+ ticks_2mhz = i_core_data_ptr->empath.tod_2mhz -
+ g_amec->proc[0].core[i_core].prev_tod_2mhz;
+ temp32 = (fin2 << 1) / ticks_2mhz;
+ // See if core is sleeping/winkled
+ if(l_core_sleep_winkle)
+ {
+ temp32 = 0;
+ }
+ sensor_update( AMECSENSOR_ARRAY_PTR(IPS2MSP0C0,i_core), (uint16_t) temp32);
+}
+
+
+// Function Specification
+//
+// Name: amec_calc_spurr
+//
+// Description: Do SPURR calculation. Must run after FreqA is calculated.
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_calc_spurr(uint8_t i_core)
+{
+ uint16_t l_actual_freq = AMECSENSOR_ARRAY_PTR(FREQA2MSP0C0, i_core)->sample;
+ uint16_t l_nominal = 2790;
+ uint32_t temp32;
+
+ // Sanity Check on Freq
+ if(l_actual_freq < UPPER_LIMIT_PROC_FREQ_MHZ)
+ {
+ temp32 = ((uint32_t) (l_actual_freq * 1000) / l_nominal);
+
+ // Scale for SPURR Register (64 = Nominal, 32 = Nom-50%)
+ temp32 = (temp32 * 64) / 1000;
+
+ sensor_update( AMECSENSOR_ARRAY_PTR(SPURR2MSP0C0,i_core), (uint16_t) temp32);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_sensors_core.h b/src/occ_405/amec/amec_sensors_core.h
new file mode 100755
index 0000000..e018925
--- /dev/null
+++ b/src/occ_405/amec/amec_sensors_core.h
@@ -0,0 +1,60 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_sensors_core.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 _AMEC_SENSORS_CORE_H
+#define _AMEC_SENSORS_CORE_H
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+#include <occ_common.h>
+#include <ssx.h>
+#include <ssx_app_cfg.h>
+#include "amec_external.h"
+#include <occ_sys_config.h>
+
+/*----------------------------------------------------------------------------*/
+/* Defines/Constants */
+/*----------------------------------------------------------------------------*/
+// See bit definition of PM State History Register for OCC
+#define OCC_PM_STATE_MASK 0x1F000000 //Mask bits 0:2 of the register
+#define OCC_PAST_FAST_SLEEP 0x18000000 //Core has been in fast sleep
+#define OCC_PAST_DEEP_SLEEP 0x1C000000 //Core has been in deep sleep
+#define OCC_PAST_FAST_WINKLE 0x1E000000 //Core has been in fast winkle
+#define OCC_PAST_DEEP_WINKLE 0x1F000000 //Core has been in deep winkle
+#define OCC_PAST_CORE_CLK_STOP 0x08000000 //Core has been in an idle state with core clocks stopped
+
+/*----------------------------------------------------------------------------*/
+/* Structures */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Function Declarations */
+/*----------------------------------------------------------------------------*/
+void amec_update_fast_core_data_sensors(void);
+
+void amec_update_proc_core_sensors(uint8_t i_core);
+
+#endif // _AMEC_SENSORS_CORE_H
diff --git a/src/occ_405/amec/amec_sensors_fw.c b/src/occ_405/amec/amec_sensors_fw.c
new file mode 100644
index 0000000..1bc3811
--- /dev/null
+++ b/src/occ_405/amec/amec_sensors_fw.c
@@ -0,0 +1,242 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_sensors_fw.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 */
+
+/******************************************************************************/
+/* Includes */
+/******************************************************************************/
+#include <occ_common.h>
+#include <ssx.h>
+#include <errl.h> // Error logging
+#include "sensor.h"
+#include "rtls.h"
+#include "occ_sys_config.h"
+#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE
+#include "dcom.h"
+#include "proc_data.h"
+#include "amec_smh.h"
+#include "amec_slave_smh.h"
+#include <trac.h>
+#include "amec_sys.h"
+#include "sensor_enum.h"
+#include "amec_service_codes.h"
+#include <amec_sensors_fw.h>
+
+/******************************************************************************/
+/* Globals */
+/******************************************************************************/
+
+//*************************************************************************
+// Code
+//*************************************************************************
+
+// Function Specification
+//
+// Name: amec_slv_update_smh_sensors
+//
+// Description: Update FW Sensors with Amec Slave Timings.
+//
+// End Function Specification
+void amec_slv_update_smh_sensors(int i_smh_state, uint32_t i_duration)
+{
+ // Update the duration in the fw timing table
+ G_fw_timing.amess_state = i_smh_state;
+ G_fw_timing.amess_dur = i_duration;
+}
+
+
+// Function Specification
+//
+// Name: amec_slv_update_gpe_sensors
+//
+// Description: Update FW Sensors with GPE Engine Timings. Called from
+// callback on GPE routine completion.
+//
+// End Function Specification
+void amec_slv_update_gpe_sensors(uint8_t i_gpe_engine)
+{
+ // Update the duration in the fw timing table
+ G_fw_timing.gpe_dur[i_gpe_engine] = DURATION_IN_US_UNTIL_NOW_FROM(G_fw_timing.rtl_start_gpe);
+}
+
+
+// Function Specification
+//
+// Name: amec_update_fw_sensors
+//
+// Description: Updates sensors related to the OCC FW Timings
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+#define MAX_CONSEC_TRACE 4
+void amec_update_fw_sensors(void)
+{
+ errlHndl_t l_err = NULL;
+ int rc = 0;
+ int rc2 = 0;
+ static bool l_first_call = TRUE;
+ bool l_gpe0_idle, l_gpe1_idle;
+ static int L_consec_trace_count = 0;
+
+ // ------------------------------------------------------
+ // Update OCC Firmware Sensors from last tick
+ // ------------------------------------------------------
+ int l_last_state = G_fw_timing.amess_state;
+ // RTLtickdur = duration of last tick's RTL ISR (max = 250us)
+ sensor_update( AMECSENSOR_PTR(RTLtickdur), G_fw_timing.rtl_dur);
+ // AMEintdur = duration of last tick's AMEC portion of RTL ISR
+ sensor_update( AMECSENSOR_PTR(AMEintdur), G_fw_timing.ameint_dur);
+ // AMESSdurX = duration of last tick's AMEC state
+ if(l_last_state >= NUM_AMEC_SMH_STATES)
+ {
+ // Sanity check. Trace this out, even though it should never happen.
+ TRAC_INFO("AMEC State Invalid, Sensor Not Updated");
+ }
+ else
+ {
+ // AMESSdurX = duration of last tick's AMEC state
+ sensor_update( AMECSENSOR_ARRAY_PTR(AMESSdur0, l_last_state), G_fw_timing.amess_dur);
+ }
+
+ // ------------------------------------------------------
+ // Kick off GPE programs to track WorstCase time in GPE
+ // and update the sensors.
+ // ------------------------------------------------------
+ if( (NULL != G_fw_timing.gpe0_timing_request)
+ && (NULL != G_fw_timing.gpe1_timing_request) )
+ {
+ //Check if both GPE engines were able to complete the last GPE job on
+ //the queue within 1 tick.
+ l_gpe0_idle = async_request_is_idle(&G_fw_timing.gpe0_timing_request->request);
+ l_gpe1_idle = async_request_is_idle(&G_fw_timing.gpe1_timing_request->request);
+ if(l_gpe0_idle && l_gpe1_idle)
+ {
+ //reset the consecutive trace count
+ L_consec_trace_count = 0;
+
+ //Both GPE engines finished on time. Now check if they were
+ //successful too.
+ if( async_request_completed(&(G_fw_timing.gpe0_timing_request->request))
+ && async_request_completed(&(G_fw_timing.gpe1_timing_request->request)) )
+ {
+ // GPEtickdur0 = duration of last tick's PORE-GPE0 duration
+ sensor_update( AMECSENSOR_PTR(GPEtickdur0), G_fw_timing.gpe_dur[0]);
+ // GPEtickdur1 = duration of last tick's PORE-GPE1 duration
+ sensor_update( AMECSENSOR_PTR(GPEtickdur1), G_fw_timing.gpe_dur[1]);
+ }
+ else
+ {
+ //This case is expected on the first call of the function.
+ //After that, this should not happen.
+ if(!l_first_call)
+ {
+ //Note: FFDC for this case is gathered by each task
+ //responsible for a GPE job.
+ TRAC_INFO("GPE task idle but GPE task did not complete");
+ }
+ l_first_call = FALSE;
+ }
+
+ // Update Time used to measure GPE duration.
+ G_fw_timing.rtl_start_gpe = G_fw_timing.rtl_start;
+
+ // Schedule the GPE Routines that will run and update the worst
+ // case timings (via callback) after they complete. These GPE
+ // routines are the last GPE routines added to the queue
+ // during the RTL tick.
+ rc = pore_flex_schedule(G_fw_timing.gpe0_timing_request);
+ rc2 = pore_flex_schedule(G_fw_timing.gpe1_timing_request);
+
+ if(rc || rc2)
+ {
+ /* @
+ * @errortype
+ * @moduleid AMEC_UPDATE_FW_SENSORS
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 return code - gpe0
+ * @userdata2 return code - gpe1
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Failure to schedule PORE-GPE poreFlex object for FW timing
+ * analysis.
+ */
+ l_err = createErrl(
+ AMEC_UPDATE_FW_SENSORS, //modId
+ SSX_GENERIC_FAILURE, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_INFORMATIONAL, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ rc, //userdata1
+ rc2); //userdata2
+
+ // commit error log
+ commitErrl( &l_err );
+ }
+ }
+ else if(L_consec_trace_count < MAX_CONSEC_TRACE)
+ {
+ uint64_t l_dbg0;
+ uint64_t l_dbg1;
+ uint64_t l_status;
+
+ // Reset will eventually be requested due to not having power measurement
+ // data after X ticks, but add some additional FFDC to the trace that
+ // will tell us what GPE job is currently executing.
+ if(!l_gpe0_idle)
+ {
+ l_dbg1 = in64(PORE_GPE0_DBG1);
+ l_dbg0 = in64(PORE_GPE0_DBG0);
+ l_status = in64(PORE_GPE0_STATUS);
+ TRAC_ERR("GPE0 programs did not complete within one tick. DBG0[0x%08x%08x] DBG1[0x%08x%08x]",
+ (uint32_t)(l_dbg0 >> 32),
+ (uint32_t)(l_dbg0 & 0x00000000ffffffffull),
+ (uint32_t)(l_dbg1 >> 32),
+ (uint32_t)(l_dbg1 & 0x00000000ffffffffull));
+ TRAC_ERR("Additional GPE0 debug data: STATUS[0x%08x%08x]",
+ (uint32_t)(l_status >> 32),
+ (uint32_t)(l_status & 0x00000000ffffffffull));
+ }
+ if(!l_gpe1_idle)
+ {
+ l_dbg1 = in64(PORE_GPE1_DBG1);
+ l_dbg0 = in64(PORE_GPE1_DBG0);
+ l_status = in64(PORE_GPE1_STATUS);
+ TRAC_ERR("GPE1 programs did not complete within one tick. DBG0[0x%08x%08x] DBG1[0x%08x%08x]",
+ (uint32_t)(l_dbg0 >> 32),
+ (uint32_t)(l_dbg0 & 0x00000000ffffffffull),
+ (uint32_t)(l_dbg1 >> 32),
+ (uint32_t)(l_dbg1 & 0x00000000ffffffffull));
+ TRAC_ERR("Additional GPE1 debug data: STATUS[0x%08x%08x]",
+ (uint32_t)(l_status >> 32),
+ (uint32_t)(l_status & 0x00000000ffffffffull));
+ }
+ L_consec_trace_count++;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_sensors_fw.h b/src/occ_405/amec/amec_sensors_fw.h
new file mode 100755
index 0000000..015cc01
--- /dev/null
+++ b/src/occ_405/amec/amec_sensors_fw.h
@@ -0,0 +1,53 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_sensors_fw.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 _AMEC_SENSORS_FW_H
+#define _AMEC_SENSORS_FW_H
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+#include <occ_common.h>
+#include <ssx.h>
+#include <ssx_app_cfg.h>
+#include "amec_external.h"
+
+/*----------------------------------------------------------------------------*/
+/* Defines/Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Function Declarations */
+/*----------------------------------------------------------------------------*/
+// Function that updates the AMEC interim structures with AMEC State Durations
+void amec_slv_update_smh_sensors(int i_smh_state, uint32_t i_duration);
+
+// Function that updates the AMEC interim structures with GPE Engine Durations
+void amec_slv_update_gpe_sensors(uint8_t i_gpe_engine);
+
+// Function that updates the AMEC FW sensors
+void amec_update_fw_sensors(void);
+
+#endif // _AMEC_SENSORS_FW_H
diff --git a/src/occ_405/amec/amec_sensors_power.c b/src/occ_405/amec/amec_sensors_power.c
new file mode 100755
index 0000000..8d08db3
--- /dev/null
+++ b/src/occ_405/amec/amec_sensors_power.c
@@ -0,0 +1,668 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_sensors_power.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 */
+
+/******************************************************************************/
+/* Includes */
+/******************************************************************************/
+#include <occ_common.h>
+#include <ssx.h>
+#include <errl.h> // Error logging
+#include "sensor.h"
+#include "rtls.h"
+#include "occ_sys_config.h"
+#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE
+#include "dcom.h"
+#include "proc_data.h"
+#include "amec_smh.h"
+#include "amec_slave_smh.h"
+#include <trac.h>
+#include "amec_sys.h"
+#include "sensor_enum.h"
+#include "amec_service_codes.h"
+#include <amec_sensors_power.h>
+#include <cmdh_snapshot.h>
+#include <vrm.h>
+#include "amec_oversub.h"
+
+/******************************************************************************/
+/* Globals */
+/******************************************************************************/
+// This holds the converted ADC Reads
+uint32_t G_lastValidAdcValue[MAX_APSS_ADC_CHANNELS] = {0};
+
+extern thrm_fru_data_t G_thrm_fru_data[DATA_FRU_MAX];
+
+// There are only MAX_APSS_ADC_CHANNELS channels. Therefore if the channel value
+// is greater then the MAX, then there was no channel associated with the function id.
+#define ADC_CONVERTED_VALUE(i_chan) \
+ ((i_chan < MAX_APSS_ADC_CHANNELS) ? G_lastValidAdcValue[i_chan] : 0)
+
+extern uint8_t G_occ_interrupt_type;
+
+//*************************************************************************
+// Code
+//*************************************************************************
+
+// Function Specification
+//
+// Name: amec_sensor_from_apss_adc
+//
+// Description: Calculates sensor from raw ADC value
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+uint32_t amec_value_from_apss_adc(uint8_t i_chan)
+{
+ uint16_t l_raw = 0;
+ uint32_t l_temp = 0;
+ uint32_t l_gain = 0;
+ uint32_t l_offset = 0;
+
+ if(i_chan != SYSCFG_INVALID_ADC_CHAN)
+ {
+ /*
+ * The APSS value is in mV or mA depending on the channel and the raw
+ * reading from the APSS must be decoded using the following info:
+ *
+ * APSS LSB: Vref/4096
+ * Full scale: (Vref - LSB) = 0xFFF
+ * Midscale: Vref/2 = 0x800
+ * Midscale - 1 LSB: Vref/2 - 1 LSB, 0x7FF
+ * Zero: 0V, 0x000
+ * Any voltage at or above Vref will will result in an ADC channel value
+ * of 0xFFF
+ *
+ * Our APSS has Vref pinned to 2.048 V
+ * LSB: 0.5 mV (minimum ADC resolution)
+ * Full scale: 2047.5 mV (0xFFF)
+ * Midscale: 1024 mV (0x800)
+ * Zero: 0V, 0x000
+ *
+ * To get the right mV reading from the raw APSS data all we need to do
+ * is divide the raw 12 bit ADC code by 2. The same logic applies if
+ * the channel is measuring power in mA.
+ *
+ * If there is an offset it will bein mV or mA depending upon the sensor
+ * and it needs to be added or subtracted from the raw value depending
+ * on it's signedness. Negative offsets are stored in 2's complement
+ * form.
+ *
+ * The gain values will be multiplied by 1000 in TMGT before being sent
+ * in the sysconfig packet. Raw gain from the MRW values are in A/V and
+ * TMGT will multiply this by 1000 before sending in the sysconfig
+ * packet to preserve precision. That makes the gain units mA/V.
+ *
+ * To apply the gain multiply the sysconfig value against the converted
+ * APSS voltage.
+ *
+ * Applying the gain to the converted APSS data gives (mV . mA)/V so we
+ * divide by 1000 to reduce the result to mA. This is the unit that
+ * is returned to the caller. For example:
+ * raw APSS value: 0x800
+ * converted value: raw/2 = 1024 mV
+ * gain from MRW: 10.00 A/V
+ * Converted gain: 10,000 mA/V
+ * gain adjusted output: 1024mV * 10,000 mA/V = 10,240,000 (mV . mA)/V
+ * Reduced value: adjusted/1000 = 10,240 mA
+ *
+ * Note that in the case of the remote ground and 12V sense the gain
+ * values are in V/V so the returned value is actually in mVs.
+ *
+ * Max returnable value is 4,294,967,295 mA or approx. 4.3 MA
+ */
+
+ // Get ADC Mapping calibration info for this entity.
+ l_gain = G_sysConfigData.apss_cal[i_chan].gain;
+ l_offset = G_sysConfigData.apss_cal[i_chan].offset;
+
+ // Read Raw Value in mA (divide masked channel data by 2)
+ l_raw = (G_dcom_slv_inbox_rx.adc[i_chan] & APSS_12BIT_ADC_MASK)/2;
+ // Apply offset and gain
+ if (l_offset & 0x80000000)
+ {
+ // Negative offset
+ l_raw -= (~l_offset + 1);
+ }
+ else
+ {
+ l_raw += l_offset;
+ }
+ //Check to see if l_raw is negative. If so, set raw to 0
+ if (l_raw & 0x8000)
+ {
+ l_raw = 0;
+ }
+
+ l_temp = ((uint32_t)l_raw * l_gain);
+ // Reduce value back to mA or mV
+ l_temp /= 1000;
+ }
+
+ AMEC_DBG("APSS ADC info: chan=%d, raw=0x%04x, offset=%d, gain=%d calibrated output=%d\n",
+ i_chan, l_raw, l_offset, l_gain, l_temp);
+
+ return l_temp;
+}
+
+#define ADCMULT_TO_UNITS 1000000
+#define ADCMULT_ROUND ADCMULT_TO_UNITS/2
+// Function Specification
+//
+// Name: amec_update_channel_sensor
+//
+// Description: Used to calculate power based on raw data obtained from APSS
+//
+// End Function Specification
+void amec_update_channel_sensor(const uint8_t i_channel)
+{
+ if (i_channel < MAX_APSS_ADC_CHANNELS)
+ {
+ if(AMECSENSOR_PTR(PWRAPSSCH0 + i_channel)->ipmi_sid != 0)
+ {
+ uint32_t l_bulk_voltage = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v);
+
+ uint32_t l_temp32 = ADC_CONVERTED_VALUE(i_channel);
+ l_temp32 = ((l_temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+ sensor_update(AMECSENSOR_PTR(PWRAPSSCH0 + i_channel), (uint16_t) l_temp32);
+ }
+ }
+}
+
+
+// Function Specification
+//
+// Name: amec_update_apss_sensors
+//
+// Description: Calculates sensor from raw ADC values obtained from APSS
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_update_apss_sensors(void)
+{
+ /*
+ * Removed fake apss config data, do not reuse, the old hardcoded
+ * values will not work with the new code used in processing APSS channel
+ * data.
+ * Code is in place to receive command code 0x21 SET CONFIG DATA
+ * which should popluate the ADC and GPIO maps as well as the APSS
+ * calibration data for all 16 ADC channels.
+ */
+ // Need to check to make sure APSS data has been received
+ // via slave inbox first
+ if (G_slv_inbox_received)
+ {
+ uint8_t l_proc = G_pob_id.module_id;
+ uint32_t temp32 = 0;
+ uint8_t l_idx = 0;
+ uint32_t l_bulk_current_sum = 0;
+
+ // ----------------------------------------------------
+ // Convert all ADC Channels immediately
+ // ----------------------------------------------------
+ for (l_idx = 0; l_idx < MAX_APSS_ADC_CHANNELS; l_idx++)
+ {
+ // These values returned are gain adjusted. The APSS readings for
+ // the remote ground and 12V sense are returned in mVs, all other
+ // readings are treated as mAs.
+ G_lastValidAdcValue[l_idx] = amec_value_from_apss_adc(l_idx);
+
+ // Add up all channels now, we will subtract ones later that don't
+ // count towards the system power
+ l_bulk_current_sum += G_lastValidAdcValue[l_idx];
+ }
+
+ //Only for FSP-LESS systems do we update channel sensors.
+ if (FSP_SUPPORTED_OCC != G_occ_interrupt_type)
+ {
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.memory[l_proc][0]);
+ for (l_idx = 1; l_idx < MAX_PROC_CENT_CH; l_idx++)
+ {
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.memory[l_proc][l_idx]);
+ }
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.vdd[l_proc]);
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_proc]);
+
+ if (OCC_MASTER == G_occ_role)
+ {
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.io[0]);
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.io[1]);
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.io[2]);
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.fans[0]);
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.fans[1]);
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.storage_media[0]);
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.storage_media[1]);
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.total_current_12v);
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.mem_cache);
+ amec_update_channel_sensor(G_sysConfigData.apss_adc_map.gpu);
+ }
+ }
+
+ // --------------------------------------------------------------
+ // Convert 12Vsense into interim value - this has to happen first
+ // --------------------------------------------------------------
+ uint32_t l_bulk_voltage = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v);
+
+ // ----------------------------------------------------------
+ // Convert Raw Vdd/Vcs/Vio/Vpcie Power from APSS into sensors
+ // ----------------------------------------------------------
+ // Some sensor values are in Watts so after getting the mA readings we
+ // multiply by the bulk voltage (mVs) which requires us to then divide
+ // by 1000000 to get W (A.V), ie.
+ // divide by 1000 to get it back to milliUnits (0.001)
+ // divide by 10000 to get it to centiUnits (0.01)
+ // divide by 100000 to get it to deciUnits (0.1)
+ // divide by 1000000 to get it to Units (1)
+
+ //Update channel specific sensors based on saved pairing between function Ids and Channels.
+
+ uint32_t l_vdd = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vdd[l_proc]);
+ uint32_t l_vcs_vio_vpcie = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_proc]);
+ temp32 = ((l_vcs_vio_vpcie + l_vdd) * l_bulk_voltage)/ADCMULT_TO_UNITS;
+ sensor_update(AMECSENSOR_PTR(PWR250USP0), (uint16_t) temp32);
+
+ // Save off the combined power from all modules
+ for (l_idx=0; l_idx < MAX_NUM_CHIP_MODULES; l_idx++)
+ {
+ uint32_t l_vd = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vdd[l_idx]);
+ uint32_t l_vpcie = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_idx]);
+ g_amec->proc_snr_pwr[l_idx] = ((l_vpcie + l_vd) * l_bulk_voltage)/ADCMULT_TO_UNITS;
+ }
+
+ // All readings from APSS come back as milliUnits, so if we want
+ // to convert one, we need to
+ // divide by 1 to get it back to milliUnits (0.001)
+ // divide by 10 to get it to centiUnits (0.01)
+ // divide by 100 to get it to deciUnits (0.1)
+ // divide by 1000 to get it to Units (1)
+ // Vdd has both a power and a current sensor, we convert the Vdd power
+ // to Watts and the current to centiAmps
+ temp32 = ((l_vdd * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+ sensor_update( AMECSENSOR_PTR(PWR250USVDD0), (uint16_t)temp32);
+ temp32 = ((l_vcs_vio_vpcie * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+ sensor_update( AMECSENSOR_PTR(PWR250USVCS0), (uint16_t)temp32);
+
+ // ----------------------------------------------------
+ // Convert Other Raw Misc Power from APSS into sensors
+ // ----------------------------------------------------
+
+ // Fans: Add up all Fan channels
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.fans[0]);
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.fans[1]);
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+ sensor_update( AMECSENSOR_PTR(PWR250USFAN), (uint16_t)temp32);
+
+ // I/O: Add up all I/O channels
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[0]);
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[1]);
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[2]);
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+ sensor_update( AMECSENSOR_PTR(PWR250USIO), (uint16_t)temp32);
+
+ // Memory: Add up all channels for the same processor.
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][0]);
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][1]);
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][2]);
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][3]);
+ //Only for FSP-LESS systems do we add in Centaur power because it is measured on its own A/D channel, but is part of memory power
+ if (FSP_SUPPORTED_OCC != G_occ_interrupt_type)
+ {
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.mem_cache);
+ }
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+ sensor_update( AMECSENSOR_PTR(PWR250USMEM0), (uint16_t)temp32);
+
+ // Save off the combined power from all memory
+ for (l_idx=0; l_idx < MAX_NUM_CHIP_MODULES; l_idx++)
+ {
+ uint32_t l_temp = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][0]);
+ l_temp += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][1]);
+ l_temp += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][2]);
+ l_temp += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][3]);
+ g_amec->mem_snr_pwr[l_idx] = ((l_temp * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+ }
+
+ // Storage/Media
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.storage_media[0]);
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.storage_media[1]);
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+ sensor_update( AMECSENSOR_PTR(PWR250USSTORE), (uint16_t)temp32);
+
+ // GPU adapter
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.gpu);
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+ sensor_update( AMECSENSOR_PTR(PWR250USGPU), (uint16_t)temp32);
+
+ // ----------------------------------------------------
+ // Convert Raw Bulk Power from APSS into sensors
+ // ----------------------------------------------------
+ // We don't get this adc channel in some systems, we have to add it manually.
+ // With valid sysconfig data the code here should automatically use what
+ // is provided by the APSS if it is available, or manually sum it up if not.
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.total_current_12v);
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+
+ // To calculated the total 12V current based on a sum of all ADC channels,
+ // Subract adc channels that don't measure power
+ l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v);
+ l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.remote_gnd);
+
+ // If we don't have a ADC channel that measures the bulk 12v power, use
+ // the ADC sum instead
+ if(0 == temp32)
+ {
+ temp32 = ((l_bulk_current_sum * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+ }
+ sensor_update(AMECSENSOR_PTR(PWR250US), (uint16_t)temp32);
+
+ // Calculate average frequency of all OCCs.
+ uint32_t l_allOccAvgFreqOver250us = 0;
+ uint8_t l_presentOCCs = 0;
+ uint8_t l_occCount = 0;
+
+ // Add up the average freq from all OCCs.
+ for (l_occCount = 0; l_occCount < MAX_OCCS; l_occCount++)
+ {
+ if (G_sysConfigData.is_occ_present & (1<< l_occCount))
+ {
+ l_allOccAvgFreqOver250us += G_dcom_slv_outbox_rx[l_occCount].freqa2msp0;
+ l_presentOCCs++;
+ }
+ }
+ //Calculate average of all the OCCs.
+ l_allOccAvgFreqOver250us /= l_presentOCCs;
+
+ // Save the max and min pwr250us sensors and keep an accumulator of the
+ // average frequency over 30 seconds.
+ if (g_pwr250us_over30sec.count == 0)
+ {
+ //The counter has been reset, therefore initialize the stored values.
+ g_pwr250us_over30sec.max = (uint16_t) temp32;
+ g_pwr250us_over30sec.min = (uint16_t) temp32;
+ g_pwr250us_over30sec.freqaAccum = l_allOccAvgFreqOver250us;
+ }
+ else
+ {
+ //Check for max.
+ if (temp32 > g_pwr250us_over30sec.max)
+ {
+ g_pwr250us_over30sec.max = (uint16_t) temp32;
+ }
+ //Check for min.
+ if (temp32 < g_pwr250us_over30sec.min)
+ {
+ g_pwr250us_over30sec.min = (uint16_t) temp32;
+ }
+ //Average frequency accumulator.
+ g_pwr250us_over30sec.freqaAccum += l_allOccAvgFreqOver250us;
+ }
+
+ //Count of number of updates.
+ g_pwr250us_over30sec.count++;
+
+ // ----------------------------------------------------
+ // Clear Flag to indicate that AMEC has received the data.
+ // ----------------------------------------------------
+ G_slv_inbox_received = FALSE;
+ }
+ else
+ {
+ // Skip it...AMEC Health Monitor will figure out we didn't
+ // update this sensor.
+ }
+}
+
+
+// Function Specification
+//
+// Name: amec_update_vrm_sensors
+//
+// Description: Updates sensors that use data from the VRMs
+// (e.g., VR_FAN, FANS_FULL_SPEED, VR_HOT).
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_update_vrm_sensors(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ int l_rc = 0;
+ int l_vrfan = 0;
+ int l_softoc = 0;
+ int l_minus_np1_regmode = 0;
+ int l_minus_n_regmode = 0;
+ static uint8_t L_error_count = 0;
+ uint8_t l_pin_value = 1; // active low, so set default to high
+ uint8_t l_vrhot_count = 0;
+ errlHndl_t l_err = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Check if we have access to SPIVID. In DCMs only Master OCC has access to
+ // the SPIVID.
+ if (G_dcm_occ_role == OCC_DCM_MASTER)
+ {
+ // VR_FAN and SOFT_OC come from SPIVID
+ l_rc = vrm_read_state(SPIVRM_PORT(0),
+ &l_minus_np1_regmode,
+ &l_minus_n_regmode,
+ &l_vrfan,
+ &l_softoc);
+
+ if (l_rc == 0)
+ {
+ // Update the VR_FAN sensor
+ sensor_update( AMECSENSOR_PTR(VRFAN250USPROC), (uint16_t)l_vrfan );
+
+ // Clear our error count and the 'read failure' flag (since we can
+ // read VR_FAN signal)
+ L_error_count = 0;
+ G_thrm_fru_data[DATA_FRU_VRM].read_failure = 0;
+
+ // No longer reading gpio from APSS in GA1 due to instability in
+ // APSS composite mode
+ //apss_gpio_get(l_pin, &l_pin_value);
+
+ // VR_HOT sensor is a counter of number of times the VRHOT signal
+ // has been asserted
+ l_vrhot_count = AMECSENSOR_PTR(VRHOT250USPROC)->sample;
+
+ // Check if VR_FAN is asserted AND if 'fans_full_speed' GPIO is ON.
+ // Note that this GPIO is active low.
+ if (AMECSENSOR_PTR(VRFAN250USPROC)->sample && !(l_pin_value))
+ {
+ // VR_FAN is asserted and 'fans_full_speed' GPIO is ON,
+ // then increment our VR_HOT counter
+ if (l_vrhot_count < g_amec->vrhotproc.setpoint)
+ {
+ l_vrhot_count++;
+ }
+ }
+ else
+ {
+ // Reset our VR_HOT counter
+ l_vrhot_count = 0;
+ }
+ sensor_update(AMECSENSOR_PTR(VRHOT250USPROC), l_vrhot_count);
+ }
+ else
+ {
+ // Increment our error count
+ L_error_count++;
+
+ // Don't allow the error count to wrap
+ if (L_error_count == 0)
+ {
+ L_error_count = 0xFF;
+ }
+
+ // Log an error if we exceeded our number of fail-to-read sensor
+ if ((L_error_count == g_amec->proc[0].vrfan_error_count) &&
+ (g_amec->proc[0].vrfan_error_count != 0xFF))
+ {
+ TRAC_ERR("amec_update_vrm_sensors: Failed to read VR_FAN for %u consecutive times!",
+ L_error_count);
+
+ // Also, inform the thermal thread to send a cooling request
+ G_thrm_fru_data[DATA_FRU_VRM].read_failure = 1;
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_HEALTH_CHECK_VRFAN_TIMEOUT
+ * @reasoncode VRM_VRFAN_TIMEOUT
+ * @userdata1 timeout value
+ * @userdata2 0
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Failed to read VR_FAN signal from regulator.
+ *
+ */
+ l_err = createErrl(AMEC_HEALTH_CHECK_VRFAN_TIMEOUT, //modId
+ VRM_VRFAN_TIMEOUT, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ g_amec->thermaldimm.temp_timeout, //userdata1
+ 0); //userdata2
+
+ // Callout backplane for this VRM error
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.backplane_huid,
+ ERRL_CALLOUT_PRIORITY_MED);
+
+ // Commit the error
+ commitErrl(&l_err);
+ }
+ }
+ }
+
+ if( 1 )
+ {
+ sensor_update( AMECSENSOR_PTR(VRFAN250USMEM), 0 );
+ sensor_update( AMECSENSOR_PTR(VRHOT250USMEM), 0 );
+ }
+}
+
+// Function Specification
+//
+// Name: amec_update_external_voltage
+//
+// Description: Measure actual external voltage
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_update_external_voltage()
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint32_t l_data = 0;
+ uint16_t l_temp = 0;
+ uint16_t l_vdd = 0;
+ uint16_t l_vcs = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ // Collect the external voltage data
+ l_data = in32(PMC_GLOBAL_ACTUAL_VOLTAGE_REG);
+
+ // Extract the Vdd vid code and convert to voltage
+ l_temp = (l_data & 0xFF000000) >>24;
+ l_vdd = 16125 - ((uint32_t)l_temp * 625)/10;
+
+ // Extract the Vcs vid code and convert to voltage
+ l_temp = (l_data & 0x00FF0000) >>16;
+ l_vcs = 16125 - ((uint32_t)l_temp * 625)/10;
+
+ sensor_update( AMECSENSOR_PTR(VOLT250USP0V0), (uint16_t) l_vdd);
+ sensor_update( AMECSENSOR_PTR(VOLT250USP0V1), (uint16_t) l_vcs);
+}
+
+// Function Specification
+//
+// Name: amec_update_current_sensor
+//
+// Description: Estimates Vdd output current based on input power and Vdd voltage setting.
+// Compute CUR250USVDD0 (current out of Vdd regulator)
+//
+// Flow:
+//
+// Thread: RealTime Loop
+//
+// Changedby:
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_update_current_sensor(void)
+{
+ uint32_t result32; //temporary result
+ uint16_t l_pow_reg_input_dW = AMECSENSOR_PTR(PWR250USVDD0)->sample * 10; // convert to dW by *10.
+ uint16_t l_vdd_reg = AMECSENSOR_PTR(VOLT250USP0V0)->sample;
+ uint32_t l_pow_reg_output_mW;
+ uint32_t l_curr_output;
+
+
+ /* Step 1 */
+
+ // 1. Get PWR250USVDD0 (the input power to regulator)
+ // 2. Look up efficiency using PWR250USVDD0 as index (and interpolate)
+ // 3. Calculate output power = PWR250USVDD0 * efficiency
+ // 4. Calculate output current = output power / Vdd set point
+
+ /* Determine regulator efficiency */
+ // use 85% efficiency all the time
+ result32 = 8500;
+
+ // Compute regulator output power. out = in * efficiency
+ // in: min=0W max=300W = 3000dW
+ // eff: min=0 max=10000=100% (.01% units)
+ // p_out: max=3000dW * 10000 = 30,000,000 (dW*0.0001) < 2^25, fits in 25 bits
+ l_pow_reg_output_mW = (uint32_t)l_pow_reg_input_dW * (uint32_t)result32;
+ // Scale up p_out by 10x to give better resolution for the following division step
+ // p_out: max=30M (dW*0.0001) in 25 bits
+ // * 10 = 300M (dW*0.00001) in 29 bits
+ l_pow_reg_output_mW *= 10;
+ // Compute current out of regulator. curr_out = power_out (*10 scaling factor) / voltage_out
+ // p_out: max=300M (dW*0.00001) in 29 bits
+ // v_out: min=5000 (0.0001 V) max=16000(0.0001 V) in 14 bits
+ // i_out: max = 300M/5000 = 60000 (dW*0.00001/(0.0001V)= 0.01A), in 16 bits.
+ // VOLT250USP0V0 in units of 0.0001 V = 0.1 mV. (multiply by 0.1 to get mV)
+ l_curr_output = l_pow_reg_output_mW / l_vdd_reg;
+ sensor_update(AMECSENSOR_PTR(CUR250USVDD0), l_curr_output);
+
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_sensors_power.h b/src/occ_405/amec/amec_sensors_power.h
new file mode 100755
index 0000000..fd69ce8
--- /dev/null
+++ b/src/occ_405/amec/amec_sensors_power.h
@@ -0,0 +1,61 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_sensors_power.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 _AMEC_SENSORS_POWER_H
+#define _AMEC_SENSORS_POWER_H
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+#include <occ_common.h>
+#include <ssx.h>
+#include <ssx_app_cfg.h>
+#include "amec_external.h"
+
+/*----------------------------------------------------------------------------*/
+/* Defines/Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Function Declarations */
+/*----------------------------------------------------------------------------*/
+
+// Function that is called by AMEC State Machine that will update the AMEC
+// sensors for data that comes from the APSS (Power Data from APSS ADCs)
+void amec_update_apss_sensors(void);
+
+// Function that is called by AMEC State Machine that will update the AMEC
+// sensors for data that comes from the SPIVID chip (VR_FAN, SoftOC)
+void amec_update_vrm_sensors(void);
+
+// Function that is called by AMEC State Machine that will update the AMEC
+// sensors for external voltage measurement
+void amec_update_external_voltage(void);
+
+// Function that is called by AMEC State Machine that will update the AMEC
+// sensor for the Vdd output current estimation.
+void amec_update_current_sensor(void);
+
+#endif // _AMEC_SENSORS_POWER_H
diff --git a/src/occ_405/amec/amec_service_codes.h b/src/occ_405/amec/amec_service_codes.h
new file mode 100755
index 0000000..c93cc25
--- /dev/null
+++ b/src/occ_405/amec/amec_service_codes.h
@@ -0,0 +1,73 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_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 _AMEC_SERVICE_CODES_H_
+#define _AMEC_SERVICE_CODES_H_
+
+/*----------------------------------------------------------------------------*/
+/* Includes */
+/*----------------------------------------------------------------------------*/
+#include <comp_ids.h>
+
+/*----------------------------------------------------------------------------*/
+/* Constants */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Globals */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Defines */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Typedef / Enum */
+/*----------------------------------------------------------------------------*/
+enum occAmecModuleId
+{
+ AMEC_INITIALIZE_FW_SENSORS = AMEC_COMP_ID | 0x00,
+ AMEC_UPDATE_FW_SENSORS = AMEC_COMP_ID | 0x01,
+ AMEC_VECTORIZE_FW_SENSORS = AMEC_COMP_ID | 0x02,
+ AMEC_AMESTER_INTERFACE = AMEC_COMP_ID | 0x03,
+ AMEC_PCAP_CONN_OC_CONTROLLER = AMEC_COMP_ID | 0x04,
+ AMEC_MST_CHECK_PCAPS_MATCH = AMEC_COMP_ID | 0x05,
+ AMEC_MST_CHECK_UNDER_PCAP = AMEC_COMP_ID | 0x06,
+ AMEC_SLAVE_CHECK_PERFORMANCE = AMEC_COMP_ID | 0x07,
+ AMEC_HEALTH_CHECK_PROC_TEMP = AMEC_COMP_ID | 0x08,
+ AMEC_HEALTH_CHECK_DIMM_TEMP = AMEC_COMP_ID | 0x09,
+ AMEC_HEALTH_CHECK_CENT_TEMP = AMEC_COMP_ID | 0x10,
+ AMEC_HEALTH_CHECK_DIMM_TIMEOUT = AMEC_COMP_ID | 0x11,
+ AMEC_HEALTH_CHECK_CENT_TIMEOUT = AMEC_COMP_ID | 0x12,
+ AMEC_HEALTH_CHECK_VRFAN_TIMEOUT = AMEC_COMP_ID | 0x13,
+ AMEC_HEALTH_CHECK_PROC_TIMEOUT = AMEC_COMP_ID | 0x14,
+ AMEC_HEALTH_CHECK_PROC_VRHOT = AMEC_COMP_ID | 0x15,
+};
+
+/*----------------------------------------------------------------------------*/
+/* Function Prototypes */
+/*----------------------------------------------------------------------------*/
+
+#endif /* #ifndef _AMEC_SERVICE_CODES_H_ */
diff --git a/src/occ_405/amec/amec_slave_smh.c b/src/occ_405/amec/amec_slave_smh.c
new file mode 100755
index 0000000..1b5dbc0
--- /dev/null
+++ b/src/occ_405/amec/amec_slave_smh.c
@@ -0,0 +1,768 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_slave_smh.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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include <errl.h> // Error logging
+#include "sensor.h"
+#include "rtls.h"
+#include "occ_sys_config.h"
+#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE
+#include "dcom.h"
+#include "proc_data.h"
+#include "proc_data_control.h"
+#include "amec_smh.h"
+#include "amec_slave_smh.h"
+#include <trac.h>
+#include "amec_sys.h"
+#include "sensor_enum.h"
+#include "amec_service_codes.h"
+#include <amec_sensors_core.h>
+#include <amec_sensors_power.h>
+#include <amec_sensors_centaur.h>
+#include <amec_sensors_fw.h>
+#include <amec_freq.h>
+#include <amec_data.h>
+#include <centaur_data.h>
+#include <amec_amester.h>
+#include <amec_oversub.h>
+#include <amec_health.h>
+#include <amec_analytics.h>
+#include <common.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+extern dcom_slv_inbox_t G_dcom_slv_inbox_rx;
+extern uint8_t G_vrm_present;
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+smh_state_t G_amec_slv_state = {AMEC_INITIAL_STATE,
+ AMEC_INITIAL_STATE,
+ AMEC_INITIAL_STATE};
+
+// Number of ticks for periodically updating VRM-related data
+#define AMEC_UPDATE_VRM_TICKS 4000
+
+// --------------------------------------------------------
+// AMEC Slave State 6 Substate Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 16ms.
+//
+// No Substates
+//
+const smh_tbl_t amec_slv_state_6_substate_table[AMEC_SMH_STATES_PER_LVL] =
+{
+ {amec_slv_substate_6_0, NULL},
+ {amec_slv_substate_6_1, NULL},
+ {amec_slv_substate_6_2, NULL},
+ {amec_slv_substate_6_3, NULL},
+ {amec_slv_substate_6_4, NULL},
+ {amec_slv_substate_6_5, NULL},
+ {amec_slv_substate_6_6, NULL},
+ {amec_slv_substate_6_7, NULL},
+};
+
+// --------------------------------------------------------
+// AMEC Slave State 7 Substate Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 16ms.
+//
+// No Substates
+//
+const smh_tbl_t amec_slv_state_7_substate_table[AMEC_SMH_STATES_PER_LVL] =
+{
+ {amec_slv_substate_7_0, NULL},
+ {amec_slv_substate_7_1, NULL},
+ {amec_slv_substate_7_2, NULL},
+ {amec_slv_substate_7_3, NULL},
+ {amec_slv_substate_7_4, NULL},
+ {amec_slv_substate_7_5, NULL},
+ {amec_slv_substate_7_6, NULL},
+ {amec_slv_substate_7_7, NULL},
+};
+
+// --------------------------------------------------------
+// Main AMEC Slave State Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 2ms.
+//
+// No Substates
+//
+const smh_tbl_t amec_slv_state_table[AMEC_SMH_STATES_PER_LVL] =
+{
+ {amec_slv_state_0, NULL},
+ {amec_slv_state_1, NULL},
+ {amec_slv_state_2, NULL},
+ {amec_slv_state_3, NULL},
+ {amec_slv_state_4, NULL},
+ {amec_slv_state_5, NULL},
+ {amec_slv_state_6, amec_slv_state_6_substate_table},
+ {amec_slv_state_7, amec_slv_state_7_substate_table},
+};
+
+// This sets up the function pointer that will be called to update the
+// fw timings when the AMEC Slave State Machine finishes.
+smh_state_timing_t G_amec_slv_state_timings = {amec_slv_update_smh_sensors};
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// Function Specification
+//
+// Name: amec_slv_check_apss_fail
+//
+// Description: This function checks if there are APSS failures and takes
+// action accordingly. If there are APSS failures, it will lower the Pmax_rail
+// to nominal. Else, if will release the Pmax_rail.
+//
+// End Function Specification
+void amec_slv_check_apss_fail(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint32_t l_pmax_rail_freq = g_amec->proc[0].pwr_votes.apss_pmax_clip_freq;
+ Pstate l_pstate = 0;
+ static bool L_lower_pmax_rail = FALSE;
+ static bool L_raise_pmax_rail = TRUE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ if (G_apss_lower_pmax_rail == TRUE)
+ {
+ if (L_lower_pmax_rail == FALSE)
+ {
+ // Lower the Pmax_rail to nominal
+ l_pmax_rail_freq = G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL];
+ l_pstate = proc_freq2pstate(l_pmax_rail_freq);
+
+ // Set the Pmax_rail register via OCI write
+ amec_oversub_pmax_clip(l_pstate);
+
+ L_lower_pmax_rail = TRUE;
+ L_raise_pmax_rail = FALSE;
+ }
+ }
+ else
+ {
+ if (L_raise_pmax_rail == FALSE)
+ {
+ // Raise the Pmax rail back
+ l_pmax_rail_freq = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
+ l_pstate = proc_freq2pstate(l_pmax_rail_freq);
+
+ // Set the Pmax_rail register via OCI write
+ amec_oversub_pmax_clip(l_pstate);
+
+ L_lower_pmax_rail = FALSE;
+ L_raise_pmax_rail = TRUE;
+ }
+ }
+
+ // Store the frequency vote for the voting box
+ g_amec->proc[0].pwr_votes.apss_pmax_clip_freq = l_pmax_rail_freq;
+}
+
+// Function Specification
+//
+// Name: amec_slv_pstate_uplift_check
+//
+// Description: This function checks if the Global Pstate table needs to be
+// modified with a voltage uplift. If an uplift has been requested, it will
+// proceed to update every entry of the table.
+//
+// End Function Specification
+void amec_slv_pstate_uplift_check(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ Pstate l_pmin = 0;
+ Pstate l_pmax = 0;
+ uint16_t i = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Check if a new uplift request for Vdd has been made
+ if ((G_sysConfigData.vdd_vid_delta != 0) ||
+ (G_sysConfigData.vcs_vid_delta != 0))
+ {
+ TRAC_INFO("Updating Global Pstate table with requested uplift values!");
+
+ // STEP 1:
+ // Prevent any Pstate changes by locking the PMC Rail so that
+ // Pmax_rail = Pmin_rail + 1
+ l_pmin = gpst_pmin(&G_global_pstate_table) + 1;
+
+ // Set the Pmax_rail register via OCI write
+ amec_oversub_pmax_clip(l_pmin);
+
+ // STEP 2:
+ // Update all entries of the Global Pstate table using uplift provided
+ for (i=0; i<G_global_pstate_table.entries; i++)
+ {
+ // Modify the fields associated with Vdd. Per HW procedure team,
+ // the evid_vdd_eff and max_reg_vdd should get decremented
+ G_global_pstate_table.pstate[i].fields.evid_vdd += G_sysConfigData.vdd_vid_delta;
+ G_global_pstate_table.pstate[i].fields.evid_vdd_eff -= G_sysConfigData.vdd_vid_delta;
+ G_global_pstate_table.pstate[i].fields.maxreg_vdd -= G_sysConfigData.vdd_vid_delta;
+
+ // Modify the fields associated with Vcs. Per HW procedure team,
+ // the evid_vcs_eff and max_reg_vcs should get decremented
+ G_global_pstate_table.pstate[i].fields.evid_vcs += G_sysConfigData.vcs_vid_delta;
+ G_global_pstate_table.pstate[i].fields.evid_vcs_eff -= G_sysConfigData.vcs_vid_delta;
+ G_global_pstate_table.pstate[i].fields.maxreg_vcs -= G_sysConfigData.vcs_vid_delta;
+
+ // Compute the ECC for this entry
+ G_global_pstate_table.pstate[i].fields.ecc =
+ gpstCheckByte(G_global_pstate_table.pstate[i].value);
+ }
+
+ // STEP 3:
+ // Release the lock on the PMC Rail from Step 1
+ l_pmax = gpst_pmax(&G_global_pstate_table);
+
+ // Set the Pmax_rail register via OCI write
+ amec_oversub_pmax_clip(l_pmax);
+
+ // STEP 4:
+ // In order to inform the HW about the new Global Pstate table, perform
+ // a single +1 Pstate jump
+ g_amec->pstate_foverride_enable = 1;
+ if (g_amec->proc[0].core_max_freq ==
+ G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO])
+ {
+ // If we are at turbo frequency, then perform a single -1 Pstate
+ // jump instead
+ g_amec->pstate_foverride = g_amec->proc[0].core_max_freq -
+ (uint16_t)(G_global_pstate_table.frequency_step_khz / 1000);
+ }
+ else
+ {
+ g_amec->pstate_foverride = g_amec->proc[0].core_max_freq +
+ (uint16_t)(G_global_pstate_table.frequency_step_khz / 1000);
+ }
+
+ // After updating Global Pstate table, reset the delta to 0
+ G_sysConfigData.vdd_vid_delta = 0;
+ G_sysConfigData.vcs_vid_delta = 0;
+ }
+ else
+ {
+ // Check if we updated the Global Pstate table
+ if (g_amec->pstate_foverride_enable)
+ {
+ // STEP 5:
+ // Go back to the initial Pstate by disabling the override enable
+ // and maxing out the frequency request so it doesn't influence
+ // the final vote in the voting box
+ g_amec->pstate_foverride_enable = 0;
+ g_amec->pstate_foverride = 0xFFFF;
+ }
+ }
+}
+
+// Function Specification
+//
+// Name: amec_slv_common_tasks_pre
+//
+// Description: Runs all the functions that need to run pre-AMEC-State-Machine
+// This function will run every tick.
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_slv_common_tasks_pre(void)
+{
+ static uint16_t L_counter = 0;
+
+ AMEC_DBG("\tAMEC Slave Pre-State Common\n");
+
+ // Check if we need to apply a voltage uplift to the Global Pstate table
+ amec_slv_pstate_uplift_check();
+
+ // Update the FW Worst Case sensors every tick
+ amec_update_fw_sensors();
+
+ // Update the fast core data sensors every tick
+ amec_update_fast_core_data_sensors();
+
+ // Update the sensors that come from the APSS every tick
+ amec_update_apss_sensors();
+
+ // Call the stream buffer recording function
+ amec_analytics_sb_recording();
+
+ // Update the sensors that come from the VRM
+ L_counter++;
+ if (L_counter == AMEC_UPDATE_VRM_TICKS)
+ {
+ if (G_vrm_present)
+ {
+ amec_update_vrm_sensors();
+ }
+ L_counter = 0;
+ }
+
+ // Update the external voltage sensors
+ amec_update_external_voltage();
+
+ // Update estimate of Vdd regulator output current
+
+ amec_update_current_sensor(); // Compute estimate for Vdd output current
+
+ // Over-subscription check
+ amec_oversub_check();
+}
+
+
+// Function Specification
+//
+// Name: amec_slv_cmmon_tasks_post
+//
+// Description: Runs all the functions that need to run post-AMEC-State-Machine
+// This function will run every tick.
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_slv_common_tasks_post(void)
+{
+ AMEC_DBG("\tAMEC Slave Post-State Common\n");
+
+ // Only execute if OCC is in the active state
+ if ( IS_OCC_STATE_ACTIVE() )
+ {
+ // Check if we need to change Pmax_clip register setting due to not
+ // getting any APSS data from Master
+ amec_slv_check_apss_fail();
+
+ // Call amec_power_control
+ amec_power_control();
+
+ // Call the OCC slave's voting box
+ amec_slv_voting_box();
+
+ // Call the frequency state machine
+ amec_slv_freq_smh();
+
+ // Call the OCC slave's memory voting box
+ amec_slv_mem_voting_box();
+
+ // Call the OCC slave's performance check
+ amec_slv_check_perf();
+
+ // Call the 250us trace recording if it has been configured via Amester.
+ // If not configured, this call will return immediately.
+ amec_tb_record(AMEC_TB_250US);
+ }
+}
+
+
+// Function Specification
+//
+// Name: amec_slv_state_0
+//
+// Description: AMEC Slave State Machine State
+//
+// End Function Specification
+void amec_slv_state_0(void)
+{
+ AMEC_DBG("\tAMEC Slave State 0\n");
+
+ //-------------------------------------------------------
+ // Update Proc Core sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_proc_core_sensors(CORE_0);
+ amec_update_proc_core_sensors(CORE_8);
+
+ //-------------------------------------------------------
+ // Update Centaur sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_centaur_sensors(CENTAUR_0);
+
+ //-------------------------------------------------------
+ // Update Sleep Count & Winkle Count Sensors
+ //-------------------------------------------------------
+ sensor_update(AMECSENSOR_PTR(SLEEPCNT2MSP0),
+ __builtin_popcount( g_amec->proc[0].sleep_cnt));
+ g_amec->proc[0].sleep_cnt = 0;
+
+ sensor_update(AMECSENSOR_PTR(WINKCNT2MSP0),
+ __builtin_popcount(g_amec->proc[0].winkle_cnt));
+ g_amec->proc[0].winkle_cnt = 0;
+
+ //-------------------------------------------------------
+ // Update vector sensors
+ //-------------------------------------------------------
+ sensor_vector_update(AMECSENSOR_PTR(TEMP2MSP0), 1);
+ sensor_vector_update(AMECSENSOR_PTR(TEMP2MSP0PEAK),1);
+ sensor_vector_update(AMECSENSOR_PTR(FREQA2MSP0), 1);
+ sensor_vector_update(AMECSENSOR_PTR(IPS2MSP0), 1);
+ sensor_vector_update(AMECSENSOR_PTR(UTIL2MSP0), 1);
+
+ // Call the trace function for 2ms tracing if it has been configured via
+ // Amester. If not configured, this call will return immediately.
+ amec_tb_record(AMEC_TB_2MS);
+}
+
+
+// Function Specification
+//
+// Name: amec_slv_state_1
+//
+// Description: AMEC Slave State Machine State
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_slv_state_1(void)
+{
+ AMEC_DBG("\tAMEC Slave State 1\n");
+
+ //-------------------------------------------------------
+ // Update Proc Core sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_proc_core_sensors(CORE_1);
+ amec_update_proc_core_sensors(CORE_9);
+
+ //-------------------------------------------------------
+ // Update Centaur sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_centaur_sensors(CENTAUR_1);
+
+ //-------------------------------------------------------
+ // Update Proc Level Centaur/DIMM Temperature sensors
+ //-------------------------------------------------------
+ amec_update_centaur_temp_sensors();
+}
+
+
+// Function Specification
+//
+// Name: amec_slv_state_2
+//
+// Description: AMEC Slave State Machine State
+//
+// End Function Specification
+void amec_slv_state_2(void)
+{
+ AMEC_DBG("\tAMEC Slave State 2\n");
+
+ //-------------------------------------------------------
+ // Update Proc Core sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_proc_core_sensors(CORE_2);
+ amec_update_proc_core_sensors(CORE_10);
+
+ //-------------------------------------------------------
+ // Update Centaur sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_centaur_sensors(CENTAUR_2);
+}
+
+
+// Function Specification
+//
+// Name: amec_slv_state_3
+//
+// Description: AMEC Slave State Machine State
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_slv_state_3(void)
+{
+ AMEC_DBG("\tAMEC Slave State 3\n");
+
+ //-------------------------------------------------------
+ // Update Proc Core sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_proc_core_sensors(CORE_3);
+ amec_update_proc_core_sensors(CORE_11);
+
+ //-------------------------------------------------------
+ // Update Centaur sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_centaur_sensors(CENTAUR_3);
+
+ //-------------------------------------------------------
+ // Perform amec_analytics (set amec_analytics_slot to 3)
+ //-------------------------------------------------------
+ amec_analytics_main();
+}
+
+
+// Function Specification
+//
+// Name: amec_slv_state_4
+//
+// Description: AMEC Slave State Machine State
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_slv_state_4(void)
+{
+ AMEC_DBG("\tAMEC Slave State 4\n");
+
+ //-------------------------------------------------------
+ // Update Proc Core sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_proc_core_sensors(CORE_4);
+
+ //-------------------------------------------------------
+ // Update Centaur sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_centaur_sensors(CENTAUR_4);
+}
+
+
+// Function Specification
+//
+// Name: amec_slv_state_5
+//
+// Description: AMEC Slave State Machine State
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_slv_state_5(void)
+{
+ AMEC_DBG("\tAMEC Slave State 5\n");
+
+ //-------------------------------------------------------
+ // Update Proc Core sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_proc_core_sensors(CORE_5);
+
+ //-------------------------------------------------------
+ // Update Centaur sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_centaur_sensors(CENTAUR_5);
+
+ //-------------------------------------------------------
+ // Update partition sensors for DPS algorithms (for this tick)
+ //-------------------------------------------------------
+ amec_dps_main();
+}
+
+
+// Function Specification
+//
+// Name: amec_slv_state_6
+//
+// Description: AMEC Slave State Machine State
+//
+// Thread: RealTime Loop
+//
+// End Function Specification
+void amec_slv_state_6(void)
+{
+ AMEC_DBG("\tAMEC Slave State 6\n");
+
+ //-------------------------------------------------------
+ // Update Proc Core sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_proc_core_sensors(CORE_6);
+
+ //-------------------------------------------------------
+ // Update Centaur sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_centaur_sensors(CENTAUR_6);
+}
+
+
+// Function Specification
+//
+// Name: amec_slv_state_7
+//
+// Description: AMEC Slave State Machine State
+//
+// End Function Specification
+void amec_slv_state_7(void)
+{
+ AMEC_DBG("\tAMEC Slave State 7\n");
+
+ //-------------------------------------------------------
+ // Update Proc Core sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_proc_core_sensors(CORE_7);
+
+ //-------------------------------------------------------
+ // Update Centaur sensors (for this tick)
+ //-------------------------------------------------------
+ amec_update_centaur_sensors(CENTAUR_7);
+}
+
+// Function Specification
+//
+// Name: amec_slv_substate_6_0
+// amec_slv_substate_6_1
+// amec_slv_substate_6_2
+// amec_slv_substate_6_3
+// amec_slv_substate_6_4
+// amec_slv_substate_6_5
+// amec_slv_substate_6_6
+// amec_slv_substate_6_7
+//
+// Description: slave substate amec_slv_substate_6_0
+// slave substate amec_slv_substate_6_1
+// slave substate amec_slv_substate_6_2
+// slave substate amec_slv_substate_6_3
+// slave substate amec_slv_substate_6_4
+// slave substate amec_slv_substate_6_5
+// slave substate amec_slv_substate_6_6
+// slave substate amec_slv_substate_6_7
+//
+// End Function Specification
+void amec_slv_substate_6_0(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ AMEC_DBG("\tAMEC Slave State 6.0\n");
+
+ // Call processor-based thermal controller
+ amec_controller_proc_thermal();
+}
+
+void amec_slv_substate_6_1(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ AMEC_DBG("\tAMEC Slave State 6.1\n");
+
+ // Call controller on VRHOT signal from processor regulator
+ amec_controller_vrhotproc();
+}
+
+void amec_slv_substate_6_2(void){AMEC_DBG("\tAMEC Slave State 6.2\n");}
+void amec_slv_substate_6_3(void){AMEC_DBG("\tAMEC Slave State 6.3\n");}
+void amec_slv_substate_6_4(void){AMEC_DBG("\tAMEC Slave State 6.4\n");}
+void amec_slv_substate_6_5(void){AMEC_DBG("\tAMEC Slave State 6.5\n");}
+void amec_slv_substate_6_6(void){AMEC_DBG("\tAMEC Slave State 6.6\n");}
+void amec_slv_substate_6_7(void){AMEC_DBG("\tAMEC Slave State 6.7\n");}
+
+// Function Specification
+//
+// Name: amec_slv_substate_7_0
+// amec_slv_substate_7_1
+// amec_slv_substate_7_2
+// amec_slv_substate_7_3
+// amec_slv_substate_7_4
+// amec_slv_substate_7_5
+// amec_slv_substate_7_6
+// amec_slv_substate_7_7
+//
+// Description: slave substate amec_slv_substate_7_0
+// slave substate amec_slv_substate_7_1
+// slave substate amec_slv_substate_7_2
+// slave substate amec_slv_substate_7_3
+// slave substate amec_slv_substate_7_4
+// slave substate amec_slv_substate_7_5
+// slave substate amec_slv_substate_7_6
+// slave substate amec_slv_substate_7_7
+//
+// End Function Specification
+void amec_slv_substate_7_0(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ AMEC_DBG("\tAMEC Slave State 7.0\n");
+
+ // Call memory thermal controller based on DIMM temperature
+ amec_controller_dimm_thermal();
+
+ // Call memory thermal controller based on Centaur temperature
+ amec_controller_centaur_thermal();
+}
+
+void amec_slv_substate_7_1(void){AMEC_DBG("\tAMEC Slave State 7.1\n");}
+void amec_slv_substate_7_2(void){AMEC_DBG("\tAMEC Slave State 7.2\n");}
+void amec_slv_substate_7_3(void){AMEC_DBG("\tAMEC Slave State 7.3\n");}
+void amec_slv_substate_7_4(void){AMEC_DBG("\tAMEC Slave State 7.4\n");}
+void amec_slv_substate_7_5(void){AMEC_DBG("\tAMEC Slave State 7.5\n");}
+void amec_slv_substate_7_6(void){AMEC_DBG("\tAMEC Slave State 7.6\n");}
+
+void amec_slv_substate_7_7(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ AMEC_DBG("\tAMEC Slave State 7.7\n");
+
+ // Call health monitor to check for processor error temperature conditions
+ amec_health_check_proc_temp();
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_slave_smh.h b/src/occ_405/amec/amec_slave_smh.h
new file mode 100755
index 0000000..884d480
--- /dev/null
+++ b/src/occ_405/amec/amec_slave_smh.h
@@ -0,0 +1,110 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_slave_smh.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 _AMEC_SLAVE_SMH_H
+#define _AMEC_SLAVE_SMH_H
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include <ssx_app_cfg.h>
+#include <amec_smh.h>
+#include <amec_amester.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+#define AMEC_SLV_STATE() AMEC_STATE(&G_amec_slv_state);
+#define AMEC_SLV_SUBSTATE() AMEC_SUBSTATE(&G_amec_slv_state);
+#define AMEC_SLV_SUB_SUBSTATE() AMEC_SUB_SUBSTATE(&G_amec_slv_state);
+
+#define AMEC_SLV_STATE_NEXT() AMEC_STATE_NEXT(&G_amec_slv_state);
+#define AMEC_SLV_SUBSTATE_NEXT() AMEC_SUBSTATE_NEXT(&G_amec_slv_state);
+#define AMEC_SLV_SUB_SUBSTATE_NEXT() AMEC_SUB_SUBSTATE_NEXT(&G_amec_slv_state);
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+extern const smh_tbl_t amec_slv_state_table[AMEC_SMH_STATES_PER_LVL];
+extern smh_state_t G_amec_slv_state;
+extern smh_state_timing_t G_amec_slv_state_timings;
+extern bool G_apss_lower_pmax_rail;
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+void amec_slv_check_apss_fail(void);
+void amec_slv_pstate_uplift_check(void);
+
+// PRE: slave common tasks
+void amec_slv_common_tasks_pre(void);
+// POST: slave common tasks
+void amec_slv_common_tasks_post(void);
+
+// Slave States
+void amec_slv_state_0(void);
+void amec_slv_state_1(void);
+void amec_slv_state_2(void);
+void amec_slv_state_3(void);
+void amec_slv_state_4(void);
+void amec_slv_state_5(void);
+void amec_slv_state_6(void);
+void amec_slv_state_7(void);
+
+// Slave SubState 6
+void amec_slv_substate_6_0(void);
+void amec_slv_substate_6_1(void);
+void amec_slv_substate_6_2(void);
+void amec_slv_substate_6_3(void);
+void amec_slv_substate_6_4(void);
+void amec_slv_substate_6_5(void);
+void amec_slv_substate_6_6(void);
+void amec_slv_substate_6_7(void);
+
+// Slave SubState 7
+void amec_slv_substate_7_0(void);
+void amec_slv_substate_7_1(void);
+void amec_slv_substate_7_2(void);
+void amec_slv_substate_7_3(void);
+void amec_slv_substate_7_4(void);
+void amec_slv_substate_7_5(void);
+void amec_slv_substate_7_6(void);
+void amec_slv_substate_7_7(void);
+
+#endif
diff --git a/src/occ_405/amec/amec_smh.h b/src/occ_405/amec/amec_smh.h
new file mode 100755
index 0000000..e66c339
--- /dev/null
+++ b/src/occ_405/amec/amec_smh.h
@@ -0,0 +1,100 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_smh.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 _AMEC_SMH_H
+#define _AMEC_SMH_H
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include <ssx_app_cfg.h>
+#include "amec_external.h"
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+#define AMEC_STATE(i_state) (i_state->state);
+#define AMEC_SUBSTATE(i_state) (i_state->substate);
+#define AMEC_SUB_SUBSTATE(i_state) (i_state->sub_substate);
+
+#define AMEC_STATE_NEXT(i_state) i_state->state++; i_state->state %= AMEC_SMH_STATES_PER_LVL;
+#define AMEC_SUBSTATE_NEXT(i_state) i_state->substate++; i_state->substate %= AMEC_SMH_STATES_PER_LVL;
+#define AMEC_SUB_SUBSTATE_NEXT(i_state) i_state->sub_substate++; i_state->sub_substate %= AMEC_SMH_STATES_PER_LVL;
+
+#define AMEC_INITIAL_STATE 0
+
+#define AMEC_SMH_STATES_PER_LVL 8
+
+// Number of uS in 1 RTL tick (250=250us)
+#define AMEC_US_PER_TICK MICS_PER_TICK
+// Number of uS in 1 full period of the AMEC State Machine (2000=2mS, 8 RTL ticks)
+#define AMEC_US_PER_SMH_PERIOD (AMEC_SMH_STATES_PER_LVL * MICS_PER_TICK)
+// Number of <AMEC_US_PER_SMH_PERIOD> that happen in 1 second
+#define AMEC_SMH_PERIODS_IN_1SEC (10000000 / AMEC_US_PER_SMH_PERIOD)
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+// Each State table (including Substates) will take up 64 bytes
+// of SRAM space.
+typedef struct smh_tbl
+{
+ void (*state)();
+ const struct smh_tbl * substate;
+} smh_tbl_t;
+
+typedef struct
+{
+ uint8_t state;
+ uint8_t substate;
+ uint8_t sub_substate;
+} smh_state_t;
+
+typedef struct
+{
+ void (*update_sensor)(int, uint32_t);
+} smh_state_timing_t;
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+void amec_generic_smh(const smh_tbl_t * i_smh_tbl, smh_state_t * i_smh_state, smh_state_timing_t * i_smh_timing);
+
+#endif //_AMEC_SMH_H
diff --git a/src/occ_405/amec/amec_sys.h b/src/occ_405/amec/amec_sys.h
new file mode 100755
index 0000000..0383701
--- /dev/null
+++ b/src/occ_405/amec/amec_sys.h
@@ -0,0 +1,729 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/amec/amec_sys.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 _AMEC_SYS_H
+#define _AMEC_SYS_H
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <sensor.h>
+#include <occ_sys_config.h>
+#include <amec_part.h>
+#include <amec_perfcount.h>
+#include <mode.h>
+#include <amec_controller.h>
+#include <amec_oversub.h>
+#include <amec_amester.h>
+#include <amec_pcap.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+// This is an arbitrary number of FW probes for use internally.
+#define NUM_AMEC_FW_PROBES 8
+
+// Number of States in the AMEC State Machine (should always be 8)
+#define NUM_AMEC_SMH_STATES 8
+
+// Number of PORE-GPE Engines
+#define NUM_GPE_ENGINES 2
+#define GPE_ENGINE_0 0
+#define GPE_ENGINE_1 1
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//-------------------------------------------------------------
+// FW Sub-structure
+//-------------------------------------------------------------
+typedef struct
+{
+ // Sensors
+ sensor_t ameintdur;
+ sensor_t amessdur[NUM_AMEC_SMH_STATES];
+ sensor_t gpetickdur[NUM_GPE_ENGINES];
+ sensor_t prcdupdatedur;
+ sensor_t probe250us[NUM_AMEC_FW_PROBES];
+
+ // DPS update flag
+ // 8 bit flag: =1, no updating allowed; =0, updating is allowed
+ uint8_t dps_no_update_flag;
+
+} amec_fw_t;
+
+//-------------------------------------------------------------
+// Fan Sub-structure
+//-------------------------------------------------------------
+typedef struct
+{
+ // Sensors
+ sensor_t fanspeedavg;
+ sensor_t pwr250usfan;
+
+} amec_fans_t;
+
+//-------------------------------------------------------------
+// IO Sub-structure
+//-------------------------------------------------------------
+typedef struct
+{
+ // Sensors
+ sensor_t pwr250usio;
+
+} amec_io_t;
+
+//-------------------------------------------------------------
+// Storage Sub-structure
+//-------------------------------------------------------------
+typedef struct
+{
+ // Sensors
+ sensor_t pwr250usstore;
+
+} amec_store_t;
+
+//-------------------------------------------------------------
+// Proc Sub-structure
+//-------------------------------------------------------------
+
+typedef struct
+{
+ // Sensors
+ sensor_t uvolt250us;
+ sensor_t volt250us;
+
+} amec_vrm_t;
+
+
+typedef struct
+{
+ uint32_t wr_cnt_accum;
+ uint32_t rd_cnt_accum;
+ uint32_t pwrup_cnt_accum;
+ uint32_t act_cnt_accum;
+ uint32_t fr2_cnt_accum;
+ uint32_t l4_rd_cnt_accum;
+ uint32_t l4_wr_cnt_accum;
+ uint32_t intreq_base_accum;
+ uint32_t intreq_low_accum;
+ uint32_t intreq_med_accum;
+ uint32_t intreq_high_accum;
+
+ uint16_t fr2_cnt;
+ uint16_t act_cnt;
+ uint16_t pwrup_cnt;
+ uint16_t memwrite2ms;
+ uint16_t memread2ms;
+ uint16_t l4wr2ms;
+ uint16_t l4rd2ms;
+ uint16_t mirb2ms;
+ uint16_t mirl2ms;
+ uint16_t mirm2ms;
+ uint16_t mirh2ms;
+
+} amec_chpair_perf_counter_t;
+
+//convenient format for storing throttle settings
+typedef union
+{
+ uint32_t word32;
+ struct
+ {
+ uint32_t mba_n: 16;
+ uint32_t chip_n: 16;
+ };
+} amec_cent_mem_speed_t;
+
+typedef struct
+{
+ // Sensors
+ sensor_t mac2ms;
+ sensor_t mpu2ms;
+ sensor_t mirb2ms;
+ sensor_t mirl2ms;
+ sensor_t mirm2ms;
+ sensor_t mirh2ms;
+ sensor_t mts2ms;
+ sensor_t memsp2ms;
+ sensor_t m4rd2ms;
+ sensor_t m4wr2ms;
+
+ amec_chpair_perf_counter_t perf;
+
+ // The most recent throttle value sent to this MBA
+ // This is used to only send values to the centaur when it changes.
+ amec_cent_mem_speed_t last_mem_speed_sent;
+} amec_portpair_t;
+
+typedef struct
+{
+ uint32_t intreq_highlatency_accum;
+ uint32_t lp2exit_accum;
+
+ uint16_t mirc2ms;
+ uint16_t mlp2_2ms;
+} amec_centaur_perf_counter_t;
+
+#define FRU_SENSOR_STATUS_STALLED 0x01
+#define FRU_SENSOR_STATUS_ERROR 0x02
+#define FRU_SENSOR_STATUS_VALID_OLD 0x04
+#define FRU_TEMP_OUT_OF_RANGE 0x08
+#define FRU_SENSOR_STATUS_INVALID 0x10 //centaur only
+#define FRU_TEMP_FAST_CHANGE 0x20
+#define FRU_SENSOR_CENT_NEST_FIR6 0x40 //centaur only
+
+typedef struct
+{
+ uint8_t cur_temp;
+ uint8_t sample_age;
+ uint8_t flags;
+ // Sensor ID for reporting temperature to BMC
+ uint16_t temp_sid;
+}fru_temp_t;
+
+typedef struct
+{
+ // Sub-structures under Centaur
+ union
+ {
+ amec_portpair_t portpair[NUM_PORT_PAIRS_PER_CENTAUR];
+ amec_portpair_t mba[NUM_PORT_PAIRS_PER_CENTAUR];
+ }; // Just a different name to refer to same thing
+
+ // Sensors
+ sensor_t mlp2ms;
+ sensor_t mirc2ms;
+
+ //hottest dimm temperature behind this centaur
+ sensor_t tempdimmax;
+
+ //which of the 8 dimm temperatures was the hottest temperature
+ //(only changes when the max of tempdimmax changes)
+ sensor_t locdimmax;
+
+ // Current dimm tempuratures
+ fru_temp_t dimm_temps[NUM_DIMMS_PER_CENTAUR];
+
+ // Hottest centaur temperature for this centaur
+ fru_temp_t centaur_hottest;
+
+ // Sensor ID for reporting temperature to BMC
+ uint16_t temp_sid;
+
+ amec_centaur_perf_counter_t perf;
+
+} amec_centaur_t;
+
+typedef struct
+{
+ // Sub-structures under MemCtl
+ amec_centaur_t centaur;
+
+ // Sensors
+ sensor_t mrd2ms;
+ sensor_t mwr2ms;
+
+} amec_memctl_t;
+
+typedef struct
+{
+ //-----------------------------------
+ // Previous Tick Data
+ //-----------------------------------
+ uint32_t prev_PC_RUN_Th_CYCLES;
+
+ //-----------------------------------
+ // Calculations & Interim Data
+ //-----------------------------------
+ uint16_t util2ms_thread;
+
+} amec_core_thread_t;
+
+typedef struct
+{
+ // Sub-structures under Core
+ amec_core_perf_counter_t core_perf;
+ amec_core_thread_t thread[MAX_THREADS_PER_CORE];
+
+ //-----------------------------------
+ // Sensors
+ //-----------------------------------
+// sensor_t cpm2ms; //CPM - Commented out as requested by Malcolm
+ sensor_t freq250us;
+ sensor_t freqa2ms;
+ sensor_t ips2ms;
+ sensor_t mcpifd2ms;
+ sensor_t mcpifi2ms;
+ sensor_t spurr2ms;
+ sensor_t temp2ms;
+ sensor_t util2ms;
+ sensor_t nutil3s;
+ sensor_t mstl2ms;
+ sensor_t cmt2ms;
+ sensor_t cmbw2ms;
+ sensor_t ppic;
+ sensor_t pwrpx250us;
+
+ //-----------------------------------
+ // Previous Tick Data
+ //-----------------------------------
+ uint32_t prev_PC_RAW_CYCLES;
+ uint32_t prev_PC_RUN_CYCLES;
+ uint32_t prev_PC_DISPATCH;
+ uint32_t prev_PC_COMPLETED;
+ uint32_t prev_PC_RAW_Th_CYCLES;
+ uint32_t prev_tod_2mhz;
+ uint32_t prev_lpar_mem_cnt[4];
+ uint32_t prev_FREQ_SENS_BUSY;
+ uint32_t prev_FREQ_SENS_FINISH;
+
+ //-----------------------------------
+ // Calculations & Interim Data
+ //-----------------------------------
+ // Dispatched Instructions per Second
+ uint16_t dps;
+ // Dispatched Instruction per Cycle
+ uint16_t dpc;
+ // Instructions per Cycle
+ uint16_t ipc;
+ // Hottest DTS sensor per core
+ uint16_t dts_hottest;
+ // Counter of number of samples for calculating average utilization & frequency
+ uint16_t sample_count;
+ // Array of memory bandwidth for each LPAR
+ uint16_t membw[4];
+
+ // Average utilization over a fixed time interval
+ uint32_t avg_util;
+ // Average frequency over a fixed time interval
+ uint32_t avg_freq;
+
+ // ---------------------------------
+ // Frequency State Machine variables
+ // ---------------------------------
+ // Frequency request generated by the voting box
+ uint16_t f_request;
+ // Reason for the frequency request generated by the voting box
+ uint32_t f_reason;
+ // Current state of this core frequency state machine
+ uint8_t f_sms;
+
+} amec_core_t;
+
+//-------------------------------------------------------------
+// System-wide Sub-structure
+//-------------------------------------------------------------
+typedef struct
+{
+ // Sensors
+ //sensor_t fake_sensor[NUM_OCCS];
+ //
+} amec_master_t;
+
+
+//-------------------------------------------------------------
+// System-wide Sub-structure
+//-------------------------------------------------------------
+typedef struct
+{
+ // System Sensors
+ sensor_t tempambient;
+ sensor_t altitude;
+ sensor_t pwr250us;
+ sensor_t pwr250usgpu;
+ sensor_t pwrapssch[MAX_APSS_ADC_CHANNELS];
+
+ sensor_t vrfan250usmem;
+ sensor_t vrhot250usmem;
+ sensor_t vrfan250usproc;
+ sensor_t vrhot250usproc;
+
+ // Chip Sensors
+ sensor_t todclock0;
+ sensor_t todclock1;
+ sensor_t todclock2;
+
+ // Minimum Frequency that can be set in the current policy
+ uint16_t fmin;
+
+ // Maximum Frequency that can be set in the current policy
+ uint16_t fmax;
+
+ // Maximum speed in current policy
+ uint16_t max_speed;
+
+ // Minimum speed in current policy
+ uint16_t min_speed;
+
+ // Speed step size
+ uint16_t speed_step;
+
+ // Speed step limit
+ uint16_t speed_step_limit;
+} amec_systemwide_t;
+
+
+typedef struct
+{
+ //Maximum frequency allowed on this chip by the
+ //performance preserving boundary algorithm. Set by amec_ppb_fmax_calc
+ uint16_t ppb_fmax;
+
+ //Maximum frequency allowed on this chip by the Pmax_clip register.
+ //Set by amec_pmax_clip_controller.
+ uint16_t pmax_clip_freq;
+
+ //Maximum frequency allowed on this chip by the power capping algorithm for
+ //non-nominal cores. Set by amec_pcap_controller.
+ uint16_t proc_pcap_vote;
+
+ //Minimum frequency that power capping is allowed to lower a nominal
+ //core to. Set by amec_pcap_calc.
+ uint16_t nom_pcap_fmin;
+
+ //Maximum frequency allowed on this chip by the power capping algorithm for
+ //nominal cores. Set by amec_pcpa_controller.
+ uint16_t proc_pcap_nom_vote;
+
+ //Maximum frequency allowed on this chip by the connector overcurrent algorithm.
+ //Set by amec_conn_oc_controller.
+ uint16_t conn_oc_vote;
+
+ //Maximum frequency allowed on this chip by the Pmax_clip register.
+ //Set by amec_slv_check_apss_fail
+ uint16_t apss_pmax_clip_freq;
+
+} amec_proc_pwr_votes_t;
+
+//-------------------------------------------------------------
+// Proc Structure
+//-------------------------------------------------------------
+typedef struct
+{
+ // Sub-structures under Proc
+ amec_core_t core[MAX_NUM_CORES];
+ amec_memctl_t memctl[MAX_NUM_MEM_CONTROLLERS];
+ amec_vrm_t vrm[NUM_PROC_VRMS];
+ amec_proc_pwr_votes_t pwr_votes;
+
+ // Processor Sensors
+ sensor_t freqa2ms;
+ vectorSensor_t freqa2ms_vector;
+ sensor_t ips2ms;
+ vectorSensor_t ips2ms_vector;
+ sensor_t memsp2ms;
+ vectorSensor_t memsp2ms_vector;
+ sensor_t pwr250us;
+ sensor_t pwr250usvdd;
+ sensor_t cur250usvdd;
+ sensor_t pwr250usvcs;
+ sensor_t pwr250usmem;
+ sensor_t sleepcnt2ms;
+ sensor_t winkcnt2ms;
+ sensor_t sp250us;
+ sensor_t temp2ms;
+ vectorSensor_t temp2ms_vector;
+ sensor_t temp2mspeak;
+ vectorSensor_t temp2mspeak_vector;
+ sensor_t util2ms;
+ vectorSensor_t util2ms_vector;
+
+ // Memory Summary Sensors
+ sensor_t temp2mscent;
+ sensor_t temp2msdimm;
+ sensor_t memsp2ms_tls;
+
+ // Error count for failing to read VR_FAN signal
+ uint8_t vrfan_error_count;
+
+ // Calculations & Interim Data
+ uint16_t sleep_cnt;
+ uint16_t winkle_cnt;
+
+ uint16_t core_max_freq; // Maximum requested freq for all cores on chip.
+
+ // Parameters used through Amester interface
+ // Note: keep core arrays here, not in per-cores structure so one parameter
+ // can be used to pass array.
+ uint32_t parm_f_reason[MAX_NUM_CORES]; // per-core frequency reason
+ uint16_t parm_f_override[MAX_NUM_CORES]; // per-core frequency override in MHz
+ uint8_t parm_f_override_enable; // enable using the frequency override
+
+} amec_proc_t;
+
+
+
+//-------------------------------------------------------------
+// Mode Freq Structure
+//-------------------------------------------------------------
+typedef struct amec_mode_freq
+{
+ uint16_t fmin;
+ uint16_t fmax;
+ ///Minimum speed allowed based on fmin/fmax ratio
+ uint16_t min_speed;
+} amec_mode_freq_t;
+
+
+//-------------------------------------------------------------
+// Parameters for manufacturing commands
+//-------------------------------------------------------------
+typedef struct amec_mnfg
+{
+ ///Auto-slewing flag: enable=1, disable=0
+ uint8_t auto_slew;
+ ///Minimum frequency in MHz for auto-slewing
+ uint16_t fmin;
+ ///Maximum frequency in MHz for auto-slewing
+ uint16_t fmax;
+ ///Step size in MHz for auto-slewing
+ uint16_t fstep;
+ ///Additional delay in ticks for auto-slewing
+ uint16_t delay;
+ ///Frequency override to be sent to all slave OCCs
+ uint16_t foverride;
+ ///Counter of times we reached fmin or fmax
+ uint16_t slew_counter;
+ ///memory auto-slewing flag: enable=1, disable=0
+ bool mem_autoslew;
+ ///memory slewing count
+ uint32_t mem_slew_counter;
+} amec_mnfg_t;
+
+//-------------------------------------------------------------
+// Parameters for Idle Power Save (IPS) mode
+//-------------------------------------------------------------
+typedef struct amec_ips
+{
+ ///Enable/Disable IPS (=0:disable; =1:enable)
+ uint8_t enable;
+ ///Current 'active' state of IPS (=0:inactive; =1:active)
+ uint8_t active;
+ ///IPS frequency request to be sent to all OCC Slaves
+ uint16_t freq_request;
+ ///Utilization threshold to enter idle condition (in hundreth of a percent)
+ uint16_t entry_threshold;
+ ///Utilization threshold to exit idle condition (in hundreth of a percent)
+ uint16_t exit_threshold;
+ ///Delay time to enter idle condition (in number of samples)
+ uint32_t entry_delay;
+ ///Delay time to exit idle condition (in number of samples)
+ uint32_t exit_delay;
+}amec_ips_t;
+
+
+//-------------------------------------------------------------
+//
+// AMEC/OCC Overall System Structure -- g_amec
+//
+//-------------------------------------------------------------
+typedef struct
+{
+ //---------------------------------------------------------
+ //
+ // System Management Settings
+ //
+ //---------------------------------------------------------
+ // Global memory throttle reason
+ uint8_t mem_throttle_reason;
+ // Global memory speed request
+ uint16_t mem_speed_request;
+
+ // Flag to enable frequency override in the voting box due to Master OCC request
+ uint8_t foverride_enable;
+ // Override frequency to be used by the voting box due to Master OCC request
+ uint16_t foverride;
+ // Flag to enable frequency override in the voting box due to a Pstate table update
+ uint8_t pstate_foverride_enable;
+ // Override frequency to be used by the voting box due to a Pstate table update
+ uint16_t pstate_foverride;
+
+ // Idle Power Saver frequency request sent by Master OCC
+ uint16_t slv_ips_freq_request;
+ // Flag to indicate that the DPS parameters were overwritten by user
+ BOOLEAN slv_dps_param_overwrite;
+
+ //---------------------------------------------------------
+ //
+ // Physical Structure
+ //
+ //---------------------------------------------------------
+ // IO Data
+ amec_io_t io;
+
+ // Storage Data
+ amec_store_t storage;
+
+ // Fan Data
+ amec_fans_t fan;
+
+ // Overall System Data
+ amec_systemwide_t sys;
+
+ // Processor Card Data
+ // - This is an array of 1. This was initialized this way
+ // in the hopes of perhaps reusing some code from previous projects.
+ amec_proc_t proc[NUM_PROC_CHIPS_PER_OCC];
+
+ // OCC Firmware Data
+ amec_fw_t fw;
+
+ // Sensors on master for calculations across multiple OCCs
+ //amec_master_t mstr;
+
+ // Partition Information
+ amec_part_config_t part_config;
+ // Mode frequency table indexed by mode
+ amec_mode_freq_t part_mode_freq[OCC_INTERNAL_MODE_MAX_NUM];
+
+ //---------------------------------------------------------
+ //
+ // Control Systems
+ //
+ //---------------------------------------------------------
+ // Thermal Controller based on processor temperatures
+ amec_controller_t thermalproc;
+ // Thermal Controller based on Centaur temperatures
+ amec_controller_t thermalcent;
+ // Thermal Controller based on DIMM temperatures
+ amec_controller_t thermaldimm;
+ // Thermal Controller based on VRHOT signal from processor VRM
+ amec_controller_t vrhotproc;
+
+ // Oversubscription Status
+ oversub_status_t oversub_status;
+
+ // Parameters for manufacturing commands
+ amec_mnfg_t mnfg_parms;
+
+ // Parameters for Idle Power Save (IPS) mode
+ amec_ips_t mst_ips_parms;
+
+ // PowerCap Data
+ amec_pcap_t pcap;
+
+ // Save off proc and mem sensor data for debug usage
+ uint16_t proc_snr_pwr[MAX_NUM_CHIP_MODULES];
+ uint16_t mem_snr_pwr[MAX_NUM_CHIP_MODULES];
+
+ // save off when pcap is considered valid
+ uint8_t pcap_valid;
+
+ //---------------------------------------------------------
+ //
+ // Parameters for analytics function
+ //
+ //---------------------------------------------------------
+ // 32 bit counter of 250usec ticks
+ uint32_t r_cnt;
+ // array holding sensor ptrs for writing to stream vector
+ void *stream_vector_map[STREAM_VECTOR_SIZE_EX];
+ void * ptr_probe250us[NUM_AMEC_FW_PROBES]; // array holding ptrs to data that is read by probe250us sensors
+ // 32-bit ptr to streaming buffer which contains 16 bit elements
+ uint16_t *ptr_stream_buffer;
+ // 32-bit index for next write into streaming buffer
+ uint32_t write_stream_index;
+ // 32-bit index for next read from streaming buffer
+ uint32_t read_stream_index;
+ // stream buffer for vector recordings
+ uint16_t stream_buffer[STREAM_BUFFER_SIZE];
+ // initially 0 until recording is valid
+ uint8_t recordflag;
+ // 16-bit delay in msec before stream vector records (set to 0 to avoid delay)
+ uint16_t stream_vector_delay;
+ // 8-bit mode control for stream vector mode:
+ uint8_t stream_vector_mode; // 0=stop recording
+ // 1=record unconditionally from begin to end of buffer, then stop
+ // 2=record unconditionally forever
+ // 3=record until a checkstop event is detected
+ // 8-bit mode control for stream vector recording:
+ // 0=fastest sampling on platform: (250usec on OCC); 7=32msec
+ uint8_t stream_vector_rate;
+ // 8-bit group # that selects which group of sensors to record as a vector
+ uint8_t stream_vector_group;
+ // input from TMGT to signal a reset of the OCC is desired (!=0)
+ uint8_t reset_prep;
+ // holds current state of L4 state machine for Centaur k
+ uint16_t cent_l4_state[MAX_NUM_CENTAURS];
+ // holds current state of L4 IPL state machine for Centaur k
+ uint16_t cent_l4_ipl_state[MAX_NUM_CENTAURS];
+ // input from OCC master to signal a desire to power down the L4s (!=0)
+ uint8_t l4_powerdown_requestm;
+ // indicates which of the L4 Centaurs is being monitored by probe.
+ uint16_t probe_l4_centaur;
+ uint32_t g44_avg[MAX_NUM_CHIP_MODULES*MAX_SENSORS_ANALYTICS];
+ // parameter driven selection of analytics group
+ uint16_t analytics_group;
+ // parameter to select which chip to monitor analytics on
+ uint8_t analytics_chip;
+ // parameter to select which analytics options (=0 just selected chip)
+ uint8_t analytics_option;
+ // 8-bit value used to throw away frames until good output has been averaged in amec_analytics buffer outputs
+ uint8_t analytics_bad_output_count;
+ // Total number of chips used in analytics sensor capture
+ uint8_t analytics_total_chips;
+ // Current offset in cyclic thermal group output (8 in cycle)
+ uint8_t analytics_thermal_offset;
+ // Selects which type of Group 44 averaging is done on per thread data:
+ // default=0 (average of non-zero thread utilizations), =1 (average of N), =2 (max of N)
+ uint8_t analytics_threadmode;
+ // Has the maximum number of threads per core for this processor architecture or for SMT modes. Default=4 on P7+.
+ uint8_t analytics_threadcountmax;
+ // Which of 8 time slots that amec_analytics is called in
+ uint8_t analytics_slot;
+ // Used to hold selected analytics group
+ uint16_t analytics_array[STREAM_VECTOR_SIZE_EX];
+ // for group 44 support core bit maps of their napping cores (upper byte) and sleeping cores (lower byte)
+ uint16_t packednapsleep[MAX_NUM_CHIP_MODULES];
+ // holds the sum of all the memory power sensors (32msec)
+ uint16_t total_memory_power;
+ uint16_t probetemp[NUM_AMEC_FW_PROBES]; // array holding temporary probe data
+ uint8_t size_probe250us[NUM_AMEC_FW_PROBES]; // size of object pointed at by each probe (1 byte, 2 bytes, or 4 bytes)
+ uint8_t index_probe250us[NUM_AMEC_FW_PROBES]; // index offset to read object pointed to by each probe (only valid for size > 2)
+
+} amec_sys_t;
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+extern amec_sys_t * g_amec;
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+void amec_slave_init(void) INIT_SECTION;
+
+#endif
diff --git a/src/occ_405/amec/amec_tasks.c b/src/occ_405/amec/amec_tasks.c
new file mode 100755
index 0000000..ce306a9
--- /dev/null
+++ b/src/occ_405/amec/amec_tasks.c
@@ -0,0 +1,292 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_tasks.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 */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <occ_common.h>
+#include <ssx.h>
+#include <errl.h> // Error logging
+#include <trac.h> // Error logging
+#include "rtls.h"
+#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE
+#include "amec_smh.h"
+#include "amec_master_smh.h"
+#include "amec_slave_smh.h"
+#include "amec_sys.h"
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+/* rotate x to the left by s bits */
+uint8_t _rotl8(uint8_t val, uint8_t shift)
+{
+ return (val << shift) | (val >> (8 - shift));
+}
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// Function Specification
+//
+// Name: amec_generic_smh
+//
+// Description: Generic State Machine that allows for 8 states per level,
+// with 3 levels.
+// If State Machine gets called/incremented every 250us,
+// - Each function entry in Level 0 table runs every 2ms,
+// - Each function entry in Level 1 table will run every 16ms,
+// - Each function entry in Level 2 table will run every 128ms.
+//
+// Anything longer than that will need to be taken care of
+// inside of the states themselves.
+//
+// NULL entries are allowed, for both state functions and
+// for pointers to substate tables.
+// - If a state does not have substates, it should have NULL
+// in the substate table for the substate table pointer.
+// - If a state does not wish to run a function, it should have
+// NULL in the substate table for the function pointer.
+// - A state can have substates without having a function that
+// runs (i.e. NULL in function pointer, but valid in substate
+// table pointer)
+//
+// In addition, if i_smh_timing is not NULL and points to a
+// smh_state_timing_t structure, this state machine will grab
+// the SSX timings of each "Level 0" state and store the longest
+// time in each state in that structure.
+//
+// End Function Specification
+void amec_generic_smh(const smh_tbl_t * i_smh_tbl,
+ smh_state_t * i_smh_state,
+ smh_state_timing_t * i_smh_timing)
+{
+ uint64_t l_start = ssx_timebase_get();
+ uint8_t l_state = 0;
+
+ // ----------------------------------------------------
+ // AMEC State Machine States
+ // ----------------------------------------------------
+ if(NULL != i_smh_tbl)
+ {
+ // Read AMEC State Machine "State"
+ l_state = AMEC_STATE(i_smh_state);
+
+ AMEC_DBG("SMH: AMEC State: [%d] Mask: [%02x]\n",l_state,i_smh_state->state);
+
+ // check if state value makes sense
+ if ( l_state >= NUM_AMEC_SMH_STATES )
+ {
+ TRAC_ERR("SMH: Invalid AMEC State: [%d] Mask: [%02x]\n",l_state,i_smh_state->state);
+
+ // TODO: how to handle this situation?
+ // for now exiting function
+ return;
+ }
+
+ // If there is a function to run for this state (!NULL), run it
+ if(NULL != i_smh_tbl[(l_state)].state)
+ {
+ // Call into AMEC State (i.e State 6)
+ (*(i_smh_tbl[(l_state)].state))();
+ }
+
+ // ----------------------------------------------------
+ // AMEC State Machine Substates
+ // ----------------------------------------------------
+ if(NULL != i_smh_tbl[l_state].substate)
+ {
+ // Read AMEC State Machine "Substate"
+ uint8_t l_substate = AMEC_SUBSTATE(i_smh_state);
+
+ AMEC_DBG("\tSMH: AMEC Sub State: %d Mask: %02x\n",l_substate,i_smh_state->substate);
+
+ // check if sub state value makes sense
+ if ( l_substate >= NUM_AMEC_SMH_STATES )
+ {
+ TRAC_ERR("SMH: Invalid AMEC Sub State: [%d] Mask: [%02x]\n",l_substate,i_smh_state->substate);
+
+ // TODO: how to handle this situation?
+ // for now exiting function
+ return;
+ }
+
+ // Set up pointer to sub-state table
+ const smh_tbl_t * l_sub_state_tbl = i_smh_tbl[l_state].substate;
+
+ // If there is a function to run for this substate (!NULL), run it
+ if(NULL != (l_sub_state_tbl+l_substate)->state)
+ {
+ // Call into AMEC Substate (i.e State 6.1)
+ (*((l_sub_state_tbl+l_substate)->state))();
+ }
+
+ // ----------------------------------------------------
+ // AMEC State Machine Sub-substates
+ // ----------------------------------------------------
+ if(NULL != (l_sub_state_tbl+l_substate)->substate)
+ {
+ // Read AMEC State Machine "Sub-Substate"
+ uint8_t l_sub_substate = AMEC_SUB_SUBSTATE(i_smh_state);
+
+ AMEC_DBG("\t\tSMH: AMEC Sub Sub State: %d Mask: %02x\n",l_sub_substate,i_smh_state->sub_substate);
+
+ // check if sub sub state value makes sense
+ if ( l_sub_substate >= NUM_AMEC_SMH_STATES )
+ {
+ TRAC_ERR("SMH: Invalid AMEC Sub State: [%d] Mask: [%02x]\n",l_sub_substate,i_smh_state->substate);
+
+ // TODO: how to handle this situation?
+ // for now exiting function
+ return;
+ }
+
+ // Set up pointer to sub-state table
+ const smh_tbl_t * l_sub_substate_tbl = (l_sub_state_tbl+l_substate)->substate;
+
+ // If there is a function to run for this sub-substate (!NULL), run it
+ if(NULL != (l_sub_substate_tbl+l_sub_substate)->state)
+ {
+ // Call into AMEC Sub-Substate (i.e State 6.1.3)
+ (*((l_sub_substate_tbl+l_sub_substate)->state))();
+ }
+ }
+ }
+ }
+
+ // ------------------------------------------------------
+ // Increment the state(s) of the AMEC State Machine
+ // ------------------------------------------------------
+
+ // Bump the state as final undertaking before task ends
+ AMEC_STATE_NEXT(i_smh_state);
+ if(AMEC_INITIAL_STATE == i_smh_state->state)
+ {
+ // Only bump the substate when "state" has wrapped
+ AMEC_SUBSTATE_NEXT(i_smh_state);
+ if(AMEC_INITIAL_STATE == i_smh_state->substate)
+ {
+ // Only bump the substate when "state" & "substate" have wrapped
+ AMEC_SUB_SUBSTATE_NEXT(i_smh_state);
+ }
+ }
+
+ // ------------------------------------------------------
+ // Update the max timing of this state(s) of the AMEC State Machine
+ // ------------------------------------------------------
+ if((NULL != i_smh_timing) && (NULL != i_smh_timing->update_sensor))
+ {
+ // Calculate the duration of the state
+ uint64_t l_state_duration = DURATION_IN_US_UNTIL_NOW_FROM(l_start);
+
+ // Make a function call to update sensor with duration
+ (*((i_smh_timing)->update_sensor))(l_state,(uint32_t)l_state_duration);
+ }
+}
+
+
+// Function Specification
+//
+// Name: task_amec_master
+//
+// Description: Purpose of this function is to run all the AMEC "master-only" code
+//
+// Task Flags: RTL_FLAG_MSTR
+// RTL_FLAG_OBS
+// RTL_FLAG_ACTIVE
+// RTL_FLAG_MSTR_READY
+// RTL_FLAG_NO_APSS
+// RTL_FLAG_RUN
+//
+// End Function Specification
+void task_amec_master( task_t *i_self)
+{
+ uint64_t l_start = ssx_timebase_get();
+
+ amec_mst_common_tasks_pre();
+
+ amec_generic_smh( amec_mst_state_table, &G_amec_mst_state, &G_amec_mst_state_timings );
+
+ amec_mst_common_tasks_post();
+
+ // Add the time that this master task took to the total AMEC int task time,
+ // which already contains the slave task duration
+ G_fw_timing.ameint_dur += DURATION_IN_US_UNTIL_NOW_FROM(l_start);
+}
+
+
+// Function Specification
+//
+// Name: task_amec_slave
+//
+// Description: Purpose of this function is to run all the AMEC "slave-only" code
+//
+// Task Flags: RTL_FLAG_MSTR
+// RTL_FLAG_NONMSTR
+// RTL_FLAG_OBS
+// RTL_FLAG_ACTIVE
+// RTL_FLAG_MSTR_READY
+// RTL_FLAG_NO_APSS
+// RTL_FLAG_RUN
+//
+// End Function Specification
+void task_amec_slave( task_t *i_self)
+{
+ uint64_t l_start = ssx_timebase_get();
+
+ amec_slv_common_tasks_pre();
+
+ amec_generic_smh( amec_slv_state_table, &G_amec_slv_state, &G_amec_slv_state_timings );
+
+ amec_slv_common_tasks_post();
+
+ // Set the total AMEC int task time for this tick, to the duration of the slave tasks.
+ G_fw_timing.ameint_dur = DURATION_IN_US_UNTIL_NOW_FROM(l_start);
+}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
OpenPOWER on IntegriCloud