summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorChris Cain <cjcain@us.ibm.com>2015-11-19 12:27:03 -0600
committerWilliam A. Bryan <wilbryan@us.ibm.com>2016-01-27 16:27:07 -0600
commit1cdc7f74cf7303b2d2e7e172b0e269928def09de (patch)
treebc88add88943f8389626a04c5219d0efc3d08f17 /src
parent476a284b52f50c1d0f5a8fc637cc28a22c714185 (diff)
downloadtalos-occ-1cdc7f74cf7303b2d2e7e172b0e269928def09de.tar.gz
talos-occ-1cdc7f74cf7303b2d2e7e172b0e269928def09de.zip
Implement code to read DIMM temperatures
Change-Id: I98fc83ab1c78bd40241fe6e47a9ddeae24f78c38 RTC: 140093 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/22770 Reviewed-by: William A. Bryan <wilbryan@us.ibm.com> Tested-by: FSP CI Jenkins Reviewed-by: Martha Broyles <mbroyles@us.ibm.com> Reviewed-by: Christopher Cain <cjcain@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/gpe_err.h4
-rwxr-xr-xsrc/gpe_export.h81
-rw-r--r--src/include/registers/ocb_firmware_registers.h6
-rw-r--r--src/ipc_func_ids.h1
-rwxr-xr-xsrc/occ_405/Makefile1
-rwxr-xr-xsrc/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c48
-rwxr-xr-xsrc/occ_405/cmdh/cmdh_mnfg_intf.c3
-rwxr-xr-xsrc/occ_405/dimm/dimm.c749
-rw-r--r--src/occ_405/dimm/dimm.h69
-rwxr-xr-xsrc/occ_405/dimm/dimm_service_codes.h (renamed from src/occ_gpe1/gpe_export.h)29
-rw-r--r--src/occ_405/img_defs.mk11
-rwxr-xr-xsrc/occ_405/incl/comp_ids.h4
-rwxr-xr-xsrc/occ_405/main.c1
-rw-r--r--src/occ_405/occLinkInputFile1
-rw-r--r--src/occ_405/occ_service_codes.h7
-rwxr-xr-xsrc/occ_405/occ_sys_config.c7
-rwxr-xr-xsrc/occ_405/occ_sys_config.h7
-rwxr-xr-xsrc/occ_405/rtls/rtls.h14
-rwxr-xr-xsrc/occ_405/rtls/rtls_tables.c27
-rwxr-xr-xsrc/occ_405/state.c32
-rw-r--r--src/occ_405/topfiles.mk1
-rwxr-xr-xsrc/occ_405/trac/trac.h12
-rwxr-xr-xsrc/occ_gpe1/gpe1.h76
-rwxr-xr-xsrc/occ_gpe1/gpe1_dimm.h60
-rw-r--r--src/occ_gpe1/gpe1_dimm_read.c511
-rw-r--r--src/occ_gpe1/gpe1_dimm_reset.c223
-rw-r--r--src/occ_gpe1/gpe1_main.c6
-rw-r--r--src/occ_gpe1/ipc_func_tables.c4
-rw-r--r--src/occ_gpe1/topfiles.mk2
29 files changed, 1900 insertions, 97 deletions
diff --git a/src/gpe_err.h b/src/gpe_err.h
index 29c58ca..292e2d5 100644
--- a/src/gpe_err.h
+++ b/src/gpe_err.h
@@ -36,11 +36,13 @@
#define GPE_RC_SCOM_PUT_FAILED 0x03 // Error on a SCOM write
#define GPE_RC_INVALID_REG 0x04 // Invalid SCOM Register used
#define GPE_RC_IPC_SEND_FAILED 0x05 // Failed to send an IPC message
+#define GPE_RC_I2C_ERROR 0x06 // I2C error occurred
+#define GPE_RC_INVALID_STATE 0x07 // Invalid state for requested operation
+#define GPE_RC_NOT_COMPLETE 0x08 // Last operation did not complete
// APSS Specific gpe return Codes
#define GPE_RC_INVALID_APSS_MODE 0x40 // OCC requested undefined APSS mode
-
// Core Data Errors
#define GPE_RC_GET_CORE_DATA_FAILED 0x60 // Failed to collect core data
diff --git a/src/gpe_export.h b/src/gpe_export.h
new file mode 100755
index 0000000..6d0bfe0
--- /dev/null
+++ b/src/gpe_export.h
@@ -0,0 +1,81 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/gpe/gpe_export.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 _GPE_EXPORT_H
+#define _GPE_EXPORT_H
+
+#include "gpe_err.h"
+
+#define WORD_HIGH(data) ((uint32_t)(((uint64_t)data)>>32))
+#define WORD_LOW(data) ((uint32_t)(((uint64_t)data)&0xFFFFFFFF))
+
+
+// GPE Error structure (common to both GPEs)
+typedef struct {
+ union
+ {
+ struct {
+ uint32_t rc;
+ uint32_t addr;
+ };
+ uint64_t error;
+ };
+ uint64_t ffdc;
+} GpeErrorStruct;
+
+
+// DIMM States (GPE1)
+typedef enum
+{
+ DIMM_STATE_INIT = 0x01, // Init interrupt registers
+ DIMM_STATE_WRITE_MODE = 0x02, // Set the mode (speed and port)
+ DIMM_STATE_WRITE_ADDR = 0x03, // Write the temp sensor address
+ DIMM_STATE_INITIATE_READ = 0x04, // Start the read
+ DIMM_STATE_READ_TEMP = 0x05, // Return the sensor reading
+ DIMM_STATE_RESET_MASTER = 0x06, // Reset master
+ DIMM_STATE_RESET_SLAVE_P0 = 0x07, // Start of slave port 0 reset
+ DIMM_STATE_RESET_SLAVE_P0_WAIT = 0x08,
+ DIMM_STATE_RESET_SLAVE_P0_COMPLETE = 0x09,
+ DIMM_STATE_RESET_SLAVE_P1 = 0x0A, // Start of slave port 1 reset
+ DIMM_STATE_RESET_SLAVE_P1_WAIT = 0x0B,
+ DIMM_STATE_RESET_SLAVE_P1_COMPLETE = 0x0C,
+} DIMM_STATE;
+
+
+// DIMM State Machine arguments (GPE1)
+typedef struct
+{
+ GpeErrorStruct error;
+ uint8_t state;
+ uint8_t i2cEngine;
+ uint8_t i2cAddr;
+ uint8_t i2cPort;
+ uint8_t dimm;
+ uint8_t maxPorts;
+ uint8_t temp;
+} dimm_sm_args_t;
+
+
+#endif //_GPE_EXPORT_H
diff --git a/src/include/registers/ocb_firmware_registers.h b/src/include/registers/ocb_firmware_registers.h
index 898cf05..14c1c63 100644
--- a/src/include/registers/ocb_firmware_registers.h
+++ b/src/include/registers/ocb_firmware_registers.h
@@ -1244,9 +1244,11 @@ typedef union ocb_occmisc {
#ifdef _BIG_ENDIAN
uint32_t core_ext_intr : 1;
uint32_t spare : 15;
- uint32_t reserved1 : 16;
+ uint32_t i2cm_intr_status : 3;
+ uint32_t reserved1 : 13;
#else
- uint32_t reserved1 : 16;
+ uint32_t reserved1 : 13;
+ uint32_t i2cm_intr_status : 3;
uint32_t spare : 15;
uint32_t core_ext_intr : 1;
#endif // _BIG_ENDIAN
diff --git a/src/ipc_func_ids.h b/src/ipc_func_ids.h
index 701d3ee..729cb77 100644
--- a/src/ipc_func_ids.h
+++ b/src/ipc_func_ids.h
@@ -67,6 +67,7 @@ IPC_FUNCIDS_TABLE_START
//Functions that are only supported by GPE1 should be defined here
//These function ID's can only be sent to GPE1
IPC_FUNCIDS_ST_START(OCCHW_INST_ID_GPE1)
+ IPC_FUNC_ID(IPC_ST_DIMM_SM_FUNCID)
IPC_FUNCIDS_ST_END(OCCHW_INST_ID_GPE1)
//Functions that are only supported by GPE2 should be defined here
diff --git a/src/occ_405/Makefile b/src/occ_405/Makefile
index 633b9d1..caae6f7 100755
--- a/src/occ_405/Makefile
+++ b/src/occ_405/Makefile
@@ -54,6 +54,7 @@ LIB_DIRS = -L$(OBJDIR) \
-L$(OBJDIR)/ppc405lib \
-L$(OBJDIR)/cmdh \
-L$(OBJDIR)/dcom \
+ -L$(OBJDIR)/dimm \
-L$(OBJDIR)/errl \
-L$(OBJDIR)/pss \
-L$(OBJDIR)/rtls \
diff --git a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c
index 2abebc0..b2ac116 100755
--- a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c
+++ b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c
@@ -957,7 +957,7 @@ errlHndl_t data_store_apss_config(const cmdh_fsp_cmd_t * i_cmd_ptr,
* @userdata4 OCC_NO_EXTENDED_RC
* @devdesc OCC recieved an invalid data packet from the FSP
*/
- cmdh_build_errl_rsp(i_cmd_ptr, o_rsp_ptr, ERRL_RC_INVALID_DATA, &l_err);
+ cmdh_build_errl_rsp(i_cmd_ptr, o_rsp_ptr, ERRL_RC_INVALID_DATA, &l_err);
}
else // Version 0x20
{
@@ -1483,7 +1483,6 @@ errlHndl_t data_store_mem_cfg(const cmdh_fsp_cmd_t * i_cmd_ptr,
uint8_t l_i2c_port;
uint8_t l_i2c_addr = 0;
uint8_t l_dimm_num = 0;
- uint8_t l_centaur_num = 0;
int i;
do
@@ -1511,7 +1510,7 @@ errlHndl_t data_store_mem_cfg(const cmdh_fsp_cmd_t * i_cmd_ptr,
// Store the memory type. Memory must all be the same type, save from first and verify remaining
G_sysConfigData.mem_type = l_cmd_ptr->data_set[0].memory_type;
- if(G_sysConfigData.mem_type == 0xFF) // TODO change to MEM_TYPE_NIMBUS
+ if(G_sysConfigData.mem_type == MEM_TYPE_NIMBUS)
{
// Nimbus type -- dimm_info1 is I2C engine which must be the same
// save from first entry and verify remaining
@@ -1519,8 +1518,28 @@ errlHndl_t data_store_mem_cfg(const cmdh_fsp_cmd_t * i_cmd_ptr,
}
else
{
- // Must be cumulus type
- G_sysConfigData.mem_type = 0; // TODO change to MEM_TYPE_CUMULUS
+ // TODO - CUMULUS not supported yet
+ //G_sysConfigData.mem_type = MEM_TYPE_CUMULUS;
+
+ CMDH_TRAC_ERR("data_store_mem_cfg: Invalid mem type 0x%02X in config data packet version[0x%02X] num_data_sets[%u]",
+ l_cmd_ptr->data_set[0].memory_type,
+ l_cmd_ptr->header.version,
+ l_cmd_ptr->header.num_data_sets);
+
+ cmdh_build_errl_rsp(i_cmd_ptr, o_rsp_ptr, ERRL_RC_INVALID_DATA, &l_err);
+ break;
+ }
+
+ // Clear all sensor IDs (hw and temperature)
+ memset(G_sysConfigData.dimm_huids, 0, sizeof(G_sysConfigData.dimm_huids));
+ int memctl, dimm;
+ for(memctl=0; memctl < MAX_NUM_MEM_CONTROLLERS; ++memctl)
+ {
+ g_amec->proc[0].memctl[memctl].centaur.temp_sid = 0;
+ for(dimm=0; dimm < NUM_DIMMS_PER_CENTAUR; ++dimm)
+ {
+ g_amec->proc[0].memctl[memctl].centaur.dimm_temps[dimm].temp_sid = 0;
+ }
}
// Store the hardware sensor ID and the temperature sensor ID
@@ -1531,7 +1550,7 @@ errlHndl_t data_store_mem_cfg(const cmdh_fsp_cmd_t * i_cmd_ptr,
// Verify matching memory type and process based on memory type
if( (l_data_set->memory_type == G_sysConfigData.mem_type) &&
- (l_data_set->memory_type == 0xFF) ) // TODO change to MEM_TYPE_NIMBUS
+ (l_data_set->memory_type == MEM_TYPE_NIMBUS) )
{
// Nimbus type: dimm info is I2C Engine, I2C Port, I2C Address
l_i2c_engine = l_data_set->dimm_info1;
@@ -1577,7 +1596,7 @@ errlHndl_t data_store_mem_cfg(const cmdh_fsp_cmd_t * i_cmd_ptr,
// The location of the HW sensor ID in the 2D dimm_huids array is used to know i2c port
// and i2c address for reading the DIMM. "centaur num" index is port "dimm num" is
// translated from i2c address, we already verified the i2c addr is 0x3z above
- l_dimm_num = (l_i2c_addr & 0x0F) >> 1;
+ l_dimm_num = (l_i2c_addr & 0x0F) >> 1;
// Store the hardware sensor ID
G_sysConfigData.dimm_huids[l_i2c_port][l_dimm_num] = l_data_set->hw_sensor_id;
@@ -1591,8 +1610,16 @@ errlHndl_t data_store_mem_cfg(const cmdh_fsp_cmd_t * i_cmd_ptr,
}
else // must be cumulus and the "memory type" byte is the centaur#
{
+ CMDH_TRAC_ERR("data_store_mem_cfg: Invalid mem type 0x%02X in config data packet entry %d (entry 0 type: 0x%02X)",
+ l_data_set->memory_type, i, G_sysConfigData.mem_type);
+
+ cmdh_build_errl_rsp(i_cmd_ptr, o_rsp_ptr, ERRL_RC_INVALID_DATA, &l_err);
+ break;
+
+#if 0
+ // TODO - CUMULUS not supported yet
// per spec for cumulus memory type is the centaur# and dimm info1 is DIMM#
- l_centaur_num = l_data_set->memory_type;
+ uint8_t l_centaur_num = l_data_set->memory_type;
l_dimm_num = l_data_set->dimm_info1;
// Validate the centaur and dimm #'s for this data set
@@ -1629,6 +1656,7 @@ errlHndl_t data_store_mem_cfg(const cmdh_fsp_cmd_t * i_cmd_ptr,
l_num_dimms++;
}
+#endif
} // Cumulus
} // for each data set
} // version 0x20
@@ -1645,8 +1673,8 @@ errlHndl_t data_store_mem_cfg(const cmdh_fsp_cmd_t * i_cmd_ptr,
{
// If there were no errors, indicate that we got this data
G_data_cnfg->data_mask |= DATA_MASK_MEM_CFG;
- CMDH_TRAC_IMP("data_store_mem_cfg: Got valid mem cfg packet. cent#=%d, dimm#=%d",
- l_num_centaurs, l_num_dimms);
+ CMDH_TRAC_IMP("data_store_mem_cfg: Got valid mem cfg packet. type=0x%02X, #cent=%d, #dimm=%d",
+ G_sysConfigData.mem_type, l_num_centaurs, l_num_dimms);
// No errors so we can enable memory monitoring if the data indicates it should be enabled
if(l_cmd_ptr->header.num_data_sets == 0) // num data sets of 0 indicates memory monitoring disabled
diff --git a/src/occ_405/cmdh/cmdh_mnfg_intf.c b/src/occ_405/cmdh/cmdh_mnfg_intf.c
index a952f1b..8fd8feb 100755
--- a/src/occ_405/cmdh/cmdh_mnfg_intf.c
+++ b/src/occ_405/cmdh/cmdh_mnfg_intf.c
@@ -238,7 +238,8 @@ uint8_t cmdh_mnfg_mem_slew(const cmdh_fsp_cmd_t * i_cmd_ptr,
// If we made it here, that means we are starting up a slew run
TRAC_INFO("cmdh_mnfg_mem_slew: We are about to start auto-slewing function");
-// TEMP -- NOT SUPPORTED YET IN PHASE1
+// TEMP -- NOT SUPPORTED YET IN PHASE1
+// when implementing see dimm/dimm.c - memory_init()
/*
// Force activation of memory monitoring and control
if(!rtl_task_is_runnable(TASK_ID_CENTAUR_CONTROL))
diff --git a/src/occ_405/dimm/dimm.c b/src/occ_405/dimm/dimm.c
new file mode 100755
index 0000000..3008979
--- /dev/null
+++ b/src/occ_405/dimm/dimm.c
@@ -0,0 +1,749 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/dimm/dimm.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 */
+
+//#define DIMM_DEBUG
+
+#include <ssx.h>
+#include <occhw_async.h>
+#include <gpe_export.h>
+
+#include <trac_interface.h>
+#include <trac.h>
+#include <occ_common.h>
+#include <comp_ids.h>
+#include <occ_service_codes.h>
+#include <dimm.h>
+#include <dimm_service_codes.h>
+#include <state.h>
+#include <occ_sys_config.h>
+#include "sensor.h"
+#include "amec_sys.h"
+
+
+extern bool G_mem_monitoring_allowed;
+extern task_t G_task_table[TASK_END];
+
+uint8_t G_dimm_state = DIMM_STATE_INIT; // Curret state of DIMM state machine
+uint8_t G_maxDimmPorts = NUM_DIMM_PORTS;
+
+bool G_dimm_i2c_reset_required = false;
+uint32_t G_dimm_i2c_reset_cause = 0;
+
+#define MAX_CONSECUTIVE_DIMM_RESETS 1
+typedef struct {
+ bool disabled;
+ uint8_t errorCount;
+ uint64_t lastReading;
+} dimmData_t;
+dimmData_t G_dimm[NUM_DIMM_PORTS][NUM_DIMMS_PER_CENTAUR] = {{{false,0}}};
+
+#define DIMM_TICK (CURRENT_TICK % MAX_NUM_TICKS)
+
+// If still no i2c interrupt after MAX_TICK_COUNT_WAIT, then try next operation anyway
+#define MAX_TICK_COUNT_WAIT 2
+
+#define DIMM_AND_PORT ((G_dimm_sm_args.i2cPort<<8) | G_dimm_sm_args.dimm)
+// GPE Requests
+GpeRequest G_dimm_sm_request;
+// GPE arguments
+GPE_BUFFER(dimm_sm_args_t G_dimm_sm_args);
+
+
+// Read OCC_MISC register to see if an I2C interrupt was generated for
+// the specified engine.
+bool check_for_i2c_interrupt(const uint8_t i_engine)
+{
+ bool l_interruptTriggered = false;
+ ocb_occmisc_t occmisc;
+ occmisc.value = in32(OCB_OCCMISC);
+
+ // I2CM_INTR_STATUS has a one bit status for each engine: C, D, and E
+ if (PIB_I2C_ENGINE_E == i_engine)
+ {
+ // Engine E
+ l_interruptTriggered = occmisc.fields.i2cm_intr_status & 0x01;
+ }
+ else if (PIB_I2C_ENGINE_D == i_engine)
+ {
+ // Engine D
+ l_interruptTriggered = occmisc.fields.i2cm_intr_status & 0x02;
+ }
+ else if (PIB_I2C_ENGINE_C == i_engine)
+ {
+ // Engine C
+ l_interruptTriggered = occmisc.fields.i2cm_intr_status & 0x04;
+ }
+ else
+ {
+ // Invalid engine
+ DIMM_DBG("check_for_i2c_interrupt: invalid engine 0x%02X", i_engine);
+ }
+
+ if (!l_interruptTriggered)
+ {
+ DIMM_DBG("check_for_i2c_interrupt: no interrupt for engine 0x%02X", i_engine);
+ }
+
+ return l_interruptTriggered;
+
+} // end check_for_i2c_interrupt()
+
+
+// Determine the I2C address for specified DIMM
+uint8_t get_dimm_addr(uint8_t i_dimm)
+{
+ //if (MEMORY_TYPE_NIMBUS == G_sysConfigData.mem_type)
+ return 0x30 | (i_dimm<<1);
+}
+
+
+// Initialize the memory task data
+void memory_init()
+{
+ if(G_mem_monitoring_allowed)
+ {
+ // Check if memory task is running (default task is for NIMBUS)
+ const task_id_t mem_task = TASK_ID_DIMM_SM;
+ if(!rtl_task_is_runnable(mem_task))
+ {
+ if (MEM_TYPE_NIMBUS == G_sysConfigData.mem_type)
+ {
+ // Init DIMM state manager IPC request
+ memory_nimbus_init();
+ }
+ else
+ {
+ // TODO CUMULUS NOT SUPPORTED YET IN PHASE1
+#if 0
+ TRAC_INFO("memory_init: calling centaur_init()");
+ centaur_init(); //no rc, handles errors internally
+#endif
+ TRAC_ERR("memory_init: invalid memory type 0x%02X", G_sysConfigData.mem_type);
+ /*
+ * @errortype
+ * @moduleid DIMM_MID_MEMORY_INIT
+ * @reasoncode MEMORY_INIT_FAILED
+ * @userdata1 memory type
+ * @userdata2 0
+ * @devdesc Invalid memory type detected
+ */
+ errlHndl_t err = createErrl(DIMM_MID_MEMORY_INIT,
+ MEMORY_INIT_FAILED,
+ OCC_NO_EXTENDED_RC,
+ ERRL_SEV_PREDICTIVE,
+ NULL,
+ DEFAULT_TRACE_SIZE,
+ G_sysConfigData.mem_type,
+ 0);
+ REQUEST_RESET(err);
+ }
+
+ // check if the init resulted in a reset
+ if(isSafeStateRequested())
+ {
+ TRAC_ERR("memory_init: OCC is being reset, memory init failed (type=0x%02X)",
+ G_sysConfigData.mem_type);
+ }
+ else
+ {
+ // Initialization was successful. Set task flags to allow memory
+ // tasks to run and also prevent from doing initialization again.
+ G_task_table[mem_task].flags = MEMORY_DATA_RTL_FLAGS;
+ //G_task_table[TASK_ID_CENTAUR_CONTROL].flags = MEMORY_CONTROL_RTL_FLAGS;
+ }
+ }
+ }
+
+} // end memory_init()
+
+
+// Create DIMM state machine IPC request
+void memory_nimbus_init()
+{
+ DIMM_DBG("memory_nimbus_init: Creating request GPE1 DIMM request objects");
+ gpe_request_create(&G_dimm_sm_request,
+ &G_async_gpe_queue1, // queue
+ IPC_ST_DIMM_SM_FUNCID, // entry_point
+ &G_dimm_sm_args, // entry_point arg
+ SSX_WAIT_FOREVER, // no timeout
+ NULL, // callback
+ NULL, // callback arg
+ ASYNC_CALLBACK_IMMEDIATE); // options
+}
+
+
+// Scan all of the DIMM temps and keep track of the hottest
+void update_hottest_dimm()
+{
+ // Find/save the hottest DIMM temperature for the last set of readings
+ uint8_t hottest = 0, hottest_loc = 0;
+ int pIndex, dIndex;
+ for (pIndex = 0; pIndex < G_maxDimmPorts; ++pIndex)
+ {
+ for (dIndex = 0; dIndex < NUM_DIMMS_PER_CENTAUR; ++dIndex)
+ {
+ if (g_amec->proc[0].memctl[pIndex].centaur.dimm_temps[dIndex].cur_temp > hottest)
+ {
+ hottest = g_amec->proc[0].memctl[pIndex].centaur.dimm_temps[dIndex].cur_temp;
+ hottest_loc = (pIndex*8) + dIndex;
+ }
+ }
+ }
+
+ DIMM_DBG("update_hottest_dimm: hottest DIMM temp for this sample: %dC (loc=%d)", hottest, hottest_loc);
+ if(hottest > g_amec->proc[0].memctl[0].centaur.tempdimmax.sample_max)
+ {
+ // Save hottest DIMM location ever sampled
+ DIMM_DBG("update_hottest_dimm: Hottest DIMM ever sampled was DIMM%d %dC (prior %dC)",
+ hottest_loc, hottest, g_amec->proc[0].memctl[0].centaur.tempdimmax.sample_max);
+ sensor_update(&g_amec->proc[0].memctl[0].centaur.locdimmax, hottest_loc);
+ }
+ // Nimbus has no Centaurs, but store hottest temp in memctl[0]
+ sensor_update(&g_amec->proc[0].memctl[0].centaur.tempdimmax, hottest);
+}
+
+
+// Update current I2C port/DIMM index to next potential DIMM
+void use_next_dimm(uint8_t * i_port, uint8_t * i_dimm)
+{
+ if (++*i_dimm == NUM_DIMMS_PER_CENTAUR)
+ {
+ // Finished all DIMMs for current port, switch to new port
+ *i_port = 1 - *i_port;
+ *i_dimm = 0;
+ }
+
+ // Check if we are starting a new set of readings and if so, update hottest DIMM
+ if ((*i_port == 0) && (*i_dimm == 0))
+ {
+ update_hottest_dimm();
+ }
+}
+
+
+// Called after a failure to read a DIMM temperature. The error will
+// be counted and if threshold is reached, and error will be created with
+// the DIMM as a callout and then set flag to trigger I2C reset
+void mark_dimm_failed()
+{
+ const uint8_t port = G_dimm_sm_args.i2cPort;
+ const uint8_t dimm = G_dimm_sm_args.dimm;
+ INTR_TRAC_ERR("mark_dimm_failed: DIMM%04X failed in state %d with rc=0x%02X "
+ "(ffdc 0x%08X%08X, err_count=%d, completion_state 0x%02X)",
+ DIMM_AND_PORT, G_dimm_sm_args.state,
+ G_dimm_sm_args.error.rc,
+ WORD_HIGH(G_dimm_sm_args.error.ffdc),
+ WORD_LOW(G_dimm_sm_args.error.ffdc),
+ G_dimm[port][dimm].errorCount,
+ G_dimm_sm_request.request.completion_state);
+
+ if (++G_dimm[port][dimm].errorCount > MAX_CONSECUTIVE_DIMM_RESETS)
+ {
+ // Disable collection on this DIMM, collect FFDC and log error
+ G_dimm[port][dimm].disabled = true;
+ INTR_TRAC_ERR("mark_dimm_failed: disabling DIMM%04X due to %d consecutive errors (state=%d)",
+ DIMM_AND_PORT, G_dimm[port][dimm].errorCount, G_dimm_sm_args.state);
+ errlHndl_t l_err = NULL;
+ /*
+ * @errortype
+ * @moduleid DIMM_MID_MARK_DIMM_FAILED
+ * @reasoncode DIMM_GPE_FAILURE
+ * @userdata1 GPE returned rc code
+ * @userdata4 ERC_DIMM_COMPLETE_FAILURE
+ * @devdesc Failure writing dimm i2c mode register
+ */
+ l_err = createErrl(DIMM_MID_MARK_DIMM_FAILED,
+ DIMM_GPE_FAILURE,
+ ERC_DIMM_COMPLETE_FAILURE,
+ ERRL_SEV_INFORMATIONAL,
+ NULL,
+ DEFAULT_TRACE_SIZE,
+ G_dimm_sm_args.error.rc,
+ 0);
+ addUsrDtlsToErrl(l_err,
+ (uint8_t*)&G_dimm_sm_request.ffdc,
+ sizeof(G_dimm_sm_request.ffdc),
+ ERRL_STRUCT_VERSION_1,
+ ERRL_USR_DTL_BINARY_DATA);
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.dimm_huids[port][dimm],
+ ERRL_CALLOUT_PRIORITY_HIGH);
+ commitErrl(&l_err);
+ }
+
+ // Reset DIMM I2C engine
+ G_dimm_i2c_reset_required = true;
+ G_dimm_i2c_reset_cause = port<<24 | dimm<<16 | (G_dimm_sm_args.error.rc & 0xFFFF);
+ G_dimm_state = DIMM_STATE_RESET_MASTER;
+
+} // end mark_dimm_failed()
+
+
+// Schedule a GPE request for the specified DIMM state
+bool schedule_dimm_req(uint8_t i_state)
+{
+ bool l_scheduled = false;
+ bool scheduleRequest = true;
+
+ DIMM_DBG("dimm_sm called with state 0x%02X (tick=%d)", i_state, DIMM_TICK);
+
+ if (!async_request_is_idle(&G_dimm_sm_request.request))
+ {
+ INTR_TRAC_ERR("dimm_sm: request is not idle.");
+ }
+ else
+ {
+ switch(i_state)
+ {
+ // Init
+ case DIMM_STATE_INIT:
+ break;
+
+ // Read DIMM temp
+ case DIMM_STATE_WRITE_MODE:
+ case DIMM_STATE_WRITE_ADDR:
+ case DIMM_STATE_INITIATE_READ:
+ case DIMM_STATE_READ_TEMP:
+ break;
+
+ // I2C reset
+ case DIMM_STATE_RESET_MASTER:
+ case DIMM_STATE_RESET_SLAVE_P0:
+ case DIMM_STATE_RESET_SLAVE_P0_COMPLETE:
+ case DIMM_STATE_RESET_SLAVE_P1:
+ case DIMM_STATE_RESET_SLAVE_P1_COMPLETE:
+ break;
+
+ default:
+ INTR_TRAC_ERR("dimm_sm: Invalid state (0x%02X)", i_state);
+ errlHndl_t err = NULL;
+ /*
+ * @errortype
+ * @moduleid DIMM_MID_DIMM_SM
+ * @reasoncode DIMM_INVALID_STATE
+ * @userdata1 DIMM state
+ * @userdata2 0
+ * @devdesc Invalid DIMM I2C state requested
+ */
+ err = createErrl(DIMM_MID_DIMM_SM,
+ DIMM_INVALID_STATE,
+ OCC_NO_EXTENDED_RC,
+ ERRL_SEV_PREDICTIVE,
+ NULL,
+ DEFAULT_TRACE_SIZE,
+ i_state,
+ 0);
+ // Request reset since this should never happen.
+ REQUEST_RESET(err);
+ scheduleRequest = false;
+ break;
+ }
+
+ if (scheduleRequest)
+ {
+ // Clear errors and init common arguments for GPE
+ G_dimm_sm_args.error.error = 0;
+ G_dimm_sm_args.state = i_state;
+
+ DIMM_DBG("dimm_sm: Scheduling GPE1 DIMM I2C state 0x%02X (tick %d)", i_state, DIMM_TICK);
+ int l_rc = gpe_request_schedule(&G_dimm_sm_request);
+ if (0 == l_rc)
+ {
+ l_scheduled = true;
+ }
+ else
+ {
+ errlHndl_t l_err = NULL;
+ INTR_TRAC_ERR("dimm_sm: schedule failed w/rc=0x%08X (%d us)",
+ l_rc, (int) ((ssx_timebase_get())/(SSX_TIMEBASE_FREQUENCY_HZ/1000000)));
+ /*
+ * @errortype
+ * @moduleid DIMM_MID_DIMM_SM
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 GPE shedule returned rc code
+ * @userdata2 state
+ * @devdesc dimm_sm schedule failed
+ */
+ l_err = createErrl(DIMM_MID_DIMM_SM,
+ SSX_GENERIC_FAILURE,
+ ERC_DIMM_SCHEDULE_FAILURE,
+ ERRL_SEV_PREDICTIVE,
+ NULL,
+ DEFAULT_TRACE_SIZE,
+ l_rc,
+ i_state);
+ // Request reset since this should never happen.
+ REQUEST_RESET(l_err);
+ }
+ }
+ }
+
+ return l_scheduled;
+
+} // end schedule_dimm_req()
+
+
+// Check if the last I2C operation completed, and force failure if not
+bool check_for_i2c_failure()
+{
+ bool failed = false;
+
+ if (false == G_dimm_i2c_reset_required)
+ {
+ // Check if I2C operation is complete
+ if (ASYNC_REQUEST_STATE_COMPLETE == G_dimm_sm_request.request.completion_state)
+ {
+ // Check if I2C operation failed
+ if ((GPE_RC_SUCCESS != G_dimm_sm_args.error.rc) &&
+ (GPE_RC_NOT_COMPLETE != G_dimm_sm_args.error.rc))
+ {
+ mark_dimm_failed();
+ failed = true;
+ }
+ }
+ }
+ return failed;
+}
+
+
+// Handle the DIMM reset states
+uint8_t dimm_reset_sm()
+{
+ uint8_t nextState = G_dimm_state;
+
+ switch (G_dimm_state)
+ {
+ case DIMM_STATE_RESET_MASTER:
+ if (DIMM_TICK == 0)
+ {
+ G_dimm_sm_args.i2cEngine = G_sysConfigData.dimm_i2c_engine;
+ if (schedule_dimm_req(DIMM_STATE_RESET_MASTER))
+ {
+ nextState = DIMM_STATE_RESET_SLAVE_P0;
+ }
+ }
+ // else wait for tick 0
+ break;
+
+ case DIMM_STATE_RESET_SLAVE_P0:
+ G_dimm_sm_args.i2cPort = 0;
+ if (schedule_dimm_req(DIMM_STATE_RESET_SLAVE_P0))
+ {
+ nextState = DIMM_STATE_RESET_SLAVE_P0_WAIT;
+ }
+ break;
+
+ case DIMM_STATE_RESET_SLAVE_P0_WAIT:
+ // Delay to allow reset to complete
+ DIMM_DBG("dimm_reset_sm: waiting during slave port 0 reset");
+ nextState = DIMM_STATE_RESET_SLAVE_P0_COMPLETE;
+ break;
+
+ case DIMM_STATE_RESET_SLAVE_P0_COMPLETE:
+ if (schedule_dimm_req(DIMM_STATE_RESET_SLAVE_P0_COMPLETE))
+ {
+ if (G_maxDimmPorts > 1)
+ {
+ nextState = DIMM_STATE_RESET_SLAVE_P1;
+ }
+ else
+ {
+ // If there is only one port, skip slave port 1
+ nextState = DIMM_STATE_INIT;
+ G_dimm_i2c_reset_required = false;
+ TRAC_INFO("dimm_reset_sm: I2C reset completed (1 port)");
+ }
+ }
+ break;
+
+ case DIMM_STATE_RESET_SLAVE_P1:
+ G_dimm_sm_args.i2cPort = 1;
+ if (schedule_dimm_req(DIMM_STATE_RESET_SLAVE_P1))
+ {
+ nextState = DIMM_STATE_RESET_SLAVE_P1_WAIT;
+ }
+ break;
+
+ case DIMM_STATE_RESET_SLAVE_P1_WAIT:
+ // Delay to allow reset to complete
+ nextState = DIMM_STATE_RESET_SLAVE_P1_COMPLETE;
+ break;
+
+ case DIMM_STATE_RESET_SLAVE_P1_COMPLETE:
+ if (schedule_dimm_req(DIMM_STATE_RESET_SLAVE_P1_COMPLETE))
+ {
+ nextState = DIMM_STATE_INIT;
+ G_dimm_i2c_reset_required = false;
+ TRAC_INFO("dimm_reset_sm: I2C reset completed");
+ }
+ break;
+
+ default:
+ INTR_TRAC_ERR("dimm_reset_sm: INVALID STATE: 0x%02X when reset is required", G_dimm_state);
+ nextState = DIMM_STATE_RESET_MASTER;
+ break;
+ }
+
+ return nextState;
+
+} // end dimm_reset_sm()
+
+
+// Function Specification
+//
+// Name: task_dimm_sm
+//
+// Description: DIMM State Machine - Called every other tick to collect all of
+// the DIMM temperatures.
+//
+// Task Flags: RTL_FLAG_ACTIVE
+//
+// End Function Specification
+void task_dimm_sm(struct task *i_self)
+{
+ static uint8_t L_dimmIndex = 0x00;
+ static uint8_t L_dimmPort = 0x00;
+ static uint8_t L_notReadyCount = 0;
+#define MAX_READ_ATTEMPT 3
+ static uint8_t L_readAttempt = 0;
+ static bool L_readIssued = false;
+
+ if (G_mem_monitoring_allowed)
+ {
+ //DIMM_DBG("task_dimm_sm: request state=0x%02X, completion_state=0x%02X, abort_state=0x%02X",
+ // G_dimm_sm_request.request.state, G_dimm_sm_request.request.completion_state, G_dimm_sm_request.request.abort_state);
+
+ if (check_for_i2c_failure())
+ {
+ // After reset, move on to next DIMM
+ use_next_dimm(&L_dimmPort, &L_dimmIndex);
+ }
+
+ uint8_t nextState = G_dimm_state;
+
+ if (G_dimm_i2c_reset_required)
+ {
+ nextState = dimm_reset_sm();
+ }
+ else if (G_dimm_state == DIMM_STATE_INIT)
+ {
+ // Setup I2C Interrupt Mask Register
+ DIMM_DBG("DIMM_STATE_INIT: (I2C Engine 0x%02X, Memory Type 0x%02X)",
+ G_sysConfigData.dimm_i2c_engine, G_sysConfigData.mem_type);
+ G_dimm_sm_args.i2cEngine = G_sysConfigData.dimm_i2c_engine;
+ if (schedule_dimm_req(DIMM_STATE_INIT))
+ {
+ nextState = DIMM_STATE_WRITE_MODE;
+ }
+ }
+ else
+ {
+ bool intTriggered = check_for_i2c_interrupt(G_sysConfigData.dimm_i2c_engine);
+ if (intTriggered == false)
+ {
+ ++L_notReadyCount;
+ }
+
+ // Check if prior command completed (or timed out waiting for it)
+ if (intTriggered || (L_notReadyCount > MAX_TICK_COUNT_WAIT))
+ {
+ if (ASYNC_REQUEST_STATE_COMPLETE == G_dimm_sm_request.request.completion_state)
+ {
+ // IPC request completed, now check return code
+ if (GPE_RC_SUCCESS == G_dimm_sm_args.error.rc)
+ {
+ // last request completed without error
+ switch (G_dimm_sm_args.state)
+ {
+ case DIMM_STATE_INIT:
+ // Save max I2C ports
+ if (G_maxDimmPorts != G_dimm_sm_args.maxPorts)
+ {
+ G_maxDimmPorts = G_dimm_sm_args.maxPorts;
+ DIMM_DBG("task_dimm_sm: updating DIMM Max I2C Ports to %d", G_maxDimmPorts);
+ }
+ break;
+
+ case DIMM_STATE_READ_TEMP:
+ if (L_readIssued)
+ {
+ const uint8_t port = G_dimm_sm_args.i2cPort;
+ const uint8_t dimm = G_dimm_sm_args.dimm;
+
+ // Last DIMM read completed, update sensor and clear error count
+ DIMM_DBG("task_dimm_sm: Successfully read DIMM%04X temperature: %dC, tick %d",
+ DIMM_AND_PORT, G_dimm_sm_args.temp, DIMM_TICK);
+ g_amec->proc[0].memctl[port].centaur.dimm_temps[dimm].cur_temp = G_dimm_sm_args.temp;
+ G_dimm[port][dimm].lastReading = ((ssx_timebase_get())/(SSX_TIMEBASE_FREQUENCY_HZ/1000000));
+ G_dimm[port][dimm].errorCount = 0;
+
+ // Move on to next DIMM
+ use_next_dimm(&L_dimmPort, &L_dimmIndex);
+ L_readIssued = false;
+ }
+ break;
+
+ default:
+ // Nothing to do
+ break;
+ }
+ }
+ else
+ {
+ // last request did not return success
+ switch (G_dimm_sm_args.state)
+ {
+ case DIMM_STATE_INITIATE_READ:
+ if (++L_readAttempt < MAX_READ_ATTEMPT)
+ {
+ // The initiate_read didnt complete, retry
+ DIMM_DBG("task_dimm_sm: initiate read didn't start (%d attempts)", L_readAttempt);
+ // Force the read again
+ G_dimm_state = DIMM_STATE_INITIATE_READ;
+ nextState = G_dimm_state;
+ }
+ else
+ {
+ INTR_TRAC_ERR("task_dimm_sm: initiate read didn't start after %d attempts... forcing reset", L_readAttempt);
+ mark_dimm_failed();
+ }
+ break;
+
+ case DIMM_STATE_READ_TEMP:
+ if (L_readIssued)
+ {
+ if (++L_readAttempt < MAX_READ_ATTEMPT)
+ {
+ DIMM_DBG("task_dimm_sm: read didn't complete (%d attempts)", L_readAttempt);
+ // Force the read again
+ G_dimm_state = DIMM_STATE_READ_TEMP;
+ nextState = G_dimm_state;
+ }
+ else
+ {
+ INTR_TRAC_ERR("task_dimm_sm: read did not complete after %d attempts... forcing reset", L_readAttempt);
+ mark_dimm_failed();
+ }
+ }
+ break;
+
+ default:
+ // Nothing to do
+ break;
+ }
+ }
+ }
+ }
+
+ if (false == G_dimm_i2c_reset_required)
+ {
+ // Handle new DIMM state
+ switch (G_dimm_state)
+ {
+ case DIMM_STATE_WRITE_MODE:
+ // Only start a DIMM read on tick 0 or 8
+ if ((DIMM_TICK == 0) || (DIMM_TICK == 8))
+ {
+ // If DIMM has huid/sensor then it should be present
+ if ((0 != G_sysConfigData.dimm_huids[L_dimmPort][L_dimmIndex]) &&
+ (G_dimm[L_dimmPort][L_dimmIndex].disabled == false))
+ {
+ G_dimm_sm_args.i2cPort = L_dimmPort;
+ G_dimm_sm_args.dimm = L_dimmIndex;
+ DIMM_DBG("task_dimm_sm: Starting collection for DIMM%04X at tick %d",
+ DIMM_AND_PORT, DIMM_TICK);
+ if (schedule_dimm_req(DIMM_STATE_WRITE_MODE))
+ {
+ nextState = DIMM_STATE_WRITE_ADDR;
+ }
+ }
+ else
+ {
+ // Skip current DIMM and move on to next one
+ use_next_dimm(&L_dimmPort, &L_dimmIndex);
+ }
+ }
+ break;
+
+ case DIMM_STATE_WRITE_ADDR:
+ if (intTriggered || (L_notReadyCount > MAX_TICK_COUNT_WAIT))
+ {
+ G_dimm_sm_args.dimm = L_dimmIndex;
+ G_dimm_sm_args.i2cAddr = get_dimm_addr(L_dimmIndex);
+ if (schedule_dimm_req(DIMM_STATE_WRITE_ADDR))
+ {
+ nextState = DIMM_STATE_INITIATE_READ;
+ L_readAttempt = 0;
+ L_readIssued = false;
+ }
+ }
+ break;
+
+ case DIMM_STATE_INITIATE_READ:
+ if (intTriggered || (L_notReadyCount > MAX_TICK_COUNT_WAIT))
+ {
+ G_dimm_sm_args.dimm = L_dimmIndex;
+ if (schedule_dimm_req(DIMM_STATE_INITIATE_READ))
+ {
+ nextState = DIMM_STATE_READ_TEMP;
+ }
+ }
+ break;
+
+ case DIMM_STATE_READ_TEMP:
+ if (intTriggered || (L_notReadyCount > MAX_TICK_COUNT_WAIT))
+ {
+ if (schedule_dimm_req(DIMM_STATE_READ_TEMP))
+ {
+ L_readIssued = true;
+ nextState = DIMM_STATE_WRITE_MODE;
+ }
+ }
+ break;
+
+ default:
+ INTR_TRAC_ERR("task_dimm_sm: INVALID STATE: 0x%02X", G_dimm_state);
+ break;
+ }
+ }
+ else
+ {
+ // Previous op triggered reset
+ nextState = dimm_reset_sm();
+ }
+ }
+
+ if (nextState != G_dimm_state)
+ {
+ DIMM_DBG("task_dimm_sm: Updating state to 0x%02X (DIMM%04X) end of tick %d", nextState, (L_dimmPort<<8)|L_dimmIndex, DIMM_TICK);
+ G_dimm_state = nextState;
+ L_notReadyCount = 0;
+ }
+ }
+
+} // end task_dimm_sm()
+
+
diff --git a/src/occ_405/dimm/dimm.h b/src/occ_405/dimm/dimm.h
new file mode 100644
index 0000000..cfbb898
--- /dev/null
+++ b/src/occ_405/dimm/dimm.h
@@ -0,0 +1,69 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/dimm/dimm.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 _DIMM_H
+#define _DIMM_H
+
+#include <occ_common.h>
+#include <trac_interface.h>
+#include <errl.h>
+#include <rtls.h>
+
+#define WORD_HIGH(data) ((uint32_t)(((uint64_t)data)>>32))
+#define WORD_LOW(data) ((uint32_t)(((uint64_t)data)&0xFFFFFFFF))
+
+#define NUM_DIMM_PORTS 2
+
+typedef enum
+{
+ DIMM_READ_SUCCESS = 0x00,
+ DIMM_READ_IN_PROGRESS = 0x01,
+ DIMM_READ_SCHEDULE_FAILED = 0xFA,
+ DIMM_READ_NOT_COMPLETE = 0xFF,
+} readStatus_e;
+
+typedef enum
+{
+ PIB_I2C_ENGINE_C = 0x01,
+ PIB_I2C_ENGINE_D = 0x02,
+ PIB_I2C_ENGINE_E = 0x03,
+} PIB_I2C_ENGINE;
+
+typedef enum
+{
+ MEM_TYPE_CUMULUS = 0x00,
+ MEM_TYPE_NIMBUS = 0xFF
+} MEMORY_TYPE;
+
+// Generic memory initialization to handle init for all memory types
+void memory_init();
+
+// Nimbus specific init
+void memory_nimbus_init();
+
+// DIMM I2C state machine (for NIMBUS)
+void task_dimm_sm(struct task *i_self);
+
+#endif //_DIMM_H
diff --git a/src/occ_gpe1/gpe_export.h b/src/occ_405/dimm/dimm_service_codes.h
index 84184e7..9261d04 100755
--- a/src/occ_gpe1/gpe_export.h
+++ b/src/occ_405/dimm/dimm_service_codes.h
@@ -1,7 +1,7 @@
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
-/* $Source: src/occ_405/gpe/gpe_export.h $ */
+/* $Source: src/occ_405/dimm/dimm_service_codes.h $ */
/* */
/* OpenPOWER OnChipController Project */
/* */
@@ -23,19 +23,18 @@
/* */
/* IBM_PROLOG_END_TAG */
-#ifndef _GPE_EXPORT_H
-#define _GPE_EXPORT_H
+#ifndef _DIMM_SERVICE_CODES_H_
+#define _DIMM_SERVICE_CODES_H_
-typedef struct {
- union
- {
- struct {
- uint32_t rc;
- uint32_t addr;
- };
- uint64_t error;
- };
- uint64_t ffdc;
-} GpeErrorStruct; // Same for every GPE program
+#include <comp_ids.h>
-#endif //_GPE_EXPORT_H
+enum dimmModuleId
+{
+ DIMM_MID_STATE_MACHINE = DIMM_COMP_ID | 0x00,
+ DIMM_MID_MEMORY_INIT = DIMM_COMP_ID | 0x01,
+ DIMM_MID_NIMBUS_INIT = DIMM_COMP_ID | 0x02,
+ DIMM_MID_DIMM_SM = DIMM_COMP_ID | 0x03,
+ DIMM_MID_MARK_DIMM_FAILED = DIMM_COMP_ID | 0x04,
+};
+
+#endif /* #ifndef _DIMM_SERVICE_CODES_H_ */
diff --git a/src/occ_405/img_defs.mk b/src/occ_405/img_defs.mk
index e3fec37..a2f6d50 100644
--- a/src/occ_405/img_defs.mk
+++ b/src/occ_405/img_defs.mk
@@ -35,10 +35,10 @@
#
# SSX_SRCDIR : Default ..; The path to the SSX source code.
# The default is set for building the SSX
-# subdirectories.
+# subdirectories.
#
# SSX_THREAD_SUPPORT : (0/1, default 1); Compile SSX thread and
-# semaphore suppprt
+# semaphore suppprt
#
# SSX_TIMER_SUPPORT : (0/1, default 1); Compile SSX timer suppprt
#
@@ -58,7 +58,7 @@
# make GCC-O-LEVEL="-Os -fno-branch-count-reg"
#
# GCC-TOOL-PREFIX : The full path (including executable file prefixes) to
-# the GCC cross-development tools to use. The default is
+# the GCC cross-development tools to use. The default is
# "ppcnf-mcp5-"
#
# CTEPATH : This variable defaults to the afs/awd CTE tool
@@ -186,8 +186,8 @@ GCC-DEFS += -DSTRAIGHT_TO_OBS_HACK=1
endif
GCC-DEFS += -DIMAGE_NAME=$(IMAGE_NAME)
-GCC-DEFS += -DSSX_TIMER_SUPPORT=$(SSX_TIMER_SUPPORT)
-GCC-DEFS += -DSSX_THREAD_SUPPORT=$(SSX_THREAD_SUPPORT)
+GCC-DEFS += -DSSX_TIMER_SUPPORT=$(SSX_TIMER_SUPPORT)
+GCC-DEFS += -DSSX_THREAD_SUPPORT=$(SSX_THREAD_SUPPORT)
GCC-DEFS += -DPPC405_MMU_SUPPORT=$(PPC405_MMU_SUPPORT)
GCC-DEFS += -DSSX_TRACE_SUPPORT=$(SSX_TRACE_SUPPORT)
GCC-DEFS += -DSSX_TRACE_HASH_PREFIX=$(SSX_TRACE_HASH_PREFIX)
@@ -212,6 +212,7 @@ APP_INCLUDES = -I$(IMAGE_SRCDIR)/rtls \
-I$(IMAGE_SRCDIR)/amec \
-I$(IMAGE_SRCDIR)/cent \
-I$(IMAGE_SRCDIR)/firdata \
+ -I$(IMAGE_SRCDIR)/dimm \
-I$(IMAGE_SRCDIR)/../occ_gpe0 \
INCLUDES += $(IMG_INCLUDES) $(GLOBAL_INCLUDES) $(APP_INCLUDES) \
diff --git a/src/occ_405/incl/comp_ids.h b/src/occ_405/incl/comp_ids.h
index fb6f5d5..e6ff8b6 100755
--- a/src/occ_405/incl/comp_ids.h
+++ b/src/occ_405/incl/comp_ids.h
@@ -80,5 +80,9 @@
#define CMDH_COMP_ID 0x0E00
#define CMDH_COMP_NAME "CMDH"
+// DIMM State Manager
+#define DIMM_COMP_ID 0x0F00
+#define DIMM_COMP_NAME "DIMM"
+
#endif
diff --git a/src/occ_405/main.c b/src/occ_405/main.c
index 2d0c37b..8e77fcf 100755
--- a/src/occ_405/main.c
+++ b/src/occ_405/main.c
@@ -56,6 +56,7 @@
#include "scom.h"
//#include <fir_data_collect.h>
#include <pss_service_codes.h>
+#include <dimm.h>
extern uint32_t __ssx_boot; // Function address is 32 bits
extern uint32_t G_occ_phantom_critical_count;
diff --git a/src/occ_405/occLinkInputFile b/src/occ_405/occLinkInputFile
index 98bec10..adc8403 100644
--- a/src/occ_405/occLinkInputFile
+++ b/src/occ_405/occLinkInputFile
@@ -20,6 +20,7 @@ INPUT ( amec_data.o
dcomMasterRx.o
dcomSlaveRx.o
dcomSlaveTx.o
+ dimm.o
errl.o
ffdc.o
fir_data_collect.o
diff --git a/src/occ_405/occ_service_codes.h b/src/occ_405/occ_service_codes.h
index 65ccde4..e355f28 100644
--- a/src/occ_405/occ_service_codes.h
+++ b/src/occ_405/occ_service_codes.h
@@ -102,6 +102,10 @@ enum occReasonCode
APSS_HARD_FAILURE = 0xC5,
/// Request to read redundant APSS data failed
REDUNDANT_APSS_GPE_FAILURE = 0xCB,
+ /// Request to read DIMM data failed.
+ DIMM_GPE_FAILURE = 0xD0,
+ MEMORY_INIT_FAILED = 0xD1,
+ DIMM_INVALID_STATE = 0xD2,
/// Success!
OCC_SUCCESS_REASON_CODE = 0xFF,
};
@@ -193,6 +197,9 @@ enum occExtReasonCode
ERC_BCE_REQ_SCHED_INPROG_FAILURE = 0x00000073,
ERC_BCE_REQ_CREATE_WRITE_FAILURE = 0x00000074,
ERC_BCE_REQ_SCHED_WRITE_FAILURE = 0x00000075,
+
+ ERC_DIMM_SCHEDULE_FAILURE = 0x00000080,
+ ERC_DIMM_COMPLETE_FAILURE = 0x00000081,
};
// Error log Module Ids
diff --git a/src/occ_405/occ_sys_config.c b/src/occ_405/occ_sys_config.c
index f052fe0..808fce0 100755
--- a/src/occ_405/occ_sys_config.c
+++ b/src/occ_405/occ_sys_config.c
@@ -26,6 +26,7 @@
#include <occ_common.h>
#include <common_types.h>
#include <occ_sys_config.h>
+#include <dimm.h>
// SysConfig Section Defines
#define SYSCFG_DEFAULT_VERSION 0xff
@@ -183,10 +184,12 @@ occSysConfigData_t G_sysConfigData =
.master_ppb_fmax = 0xFFFF,
// -----------------------------------------------------------
- // Centaur/Dimm HUID initializations
+ // Centaur/DIMM Initialization
// -----------------------------------------------------------
.centaur_huids = {0},
- .dimm_huids = {{0},{0},{0},{0},{0},{0},{0},{0}},
+ .dimm_huids = {{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}},
+ .mem_type = MEM_TYPE_NIMBUS,
+ .dimm_i2c_engine = PIB_I2C_ENGINE_E,
// -----------------------------------------------------------
// Memory Throttle Limits
diff --git a/src/occ_405/occ_sys_config.h b/src/occ_405/occ_sys_config.h
index 91a6369..4d238ee 100755
--- a/src/occ_405/occ_sys_config.h
+++ b/src/occ_405/occ_sys_config.h
@@ -34,6 +34,7 @@
#endif
#include <state.h>
#include <apss.h>
+#include <dimm.h>
#define MAX_NUM_OCC 8
#define MAX_NUM_NODES 4
@@ -332,14 +333,10 @@ typedef struct
uint32_t master_ppb_fmax;
// --------------------------------------
- // Hardware Sensor ID's for centaurs and dimms
+ // Memory Configuration Data
// --------------------------------------
uint32_t centaur_huids[MAX_NUM_CENTAURS];
uint32_t dimm_huids[MAX_NUM_CENTAURS][NUM_DIMMS_PER_CENTAUR];
-
- // --------------------------------------
- // Memory type and dimm i2c engine for nimbus
- // --------------------------------------
uint8_t mem_type;
uint8_t dimm_i2c_engine;
diff --git a/src/occ_405/rtls/rtls.h b/src/occ_405/rtls/rtls.h
index 7db2e90..5b95791 100755
--- a/src/occ_405/rtls/rtls.h
+++ b/src/occ_405/rtls/rtls.h
@@ -57,7 +57,7 @@ typedef enum {
// TASK_ID_AMEC_MASTER, // AMEC SMH tasks
// TASK_ID_CORE_DATA_CONTROL,
// TASK_ID_GPU_SM, // GPU State Machine
-// TASK_ID_DIMM_SM, // DIMM State Machine
+ TASK_ID_DIMM_SM, // DIMM State Machine
// TASK_ID_MEM_DEADMAN, // Memory deadman timer
TASK_END // This must always be the last enum in this list,
// so that TASK_END always equals the last task ID + 1.
@@ -97,13 +97,13 @@ typedef struct
RTL_FLAG_NO_APSS | RTL_FLAG_MSTR_READY | RTL_FLAG_STANDBY | \
RTL_FLAG_APSS_NOT_INITD)
-#define CENTAUR_CONTROL_RTL_FLAGS (RTL_FLAG_MSTR | RTL_FLAG_NOTMSTR | RTL_FLAG_ACTIVE | \
- RTL_FLAG_MSTR_READY | RTL_FLAG_NO_APSS | RTL_FLAG_RUN | \
- RTL_FLAG_APSS_NOT_INITD)
+#define MEMORY_CONTROL_RTL_FLAGS (RTL_FLAG_MSTR | RTL_FLAG_NOTMSTR | RTL_FLAG_ACTIVE | \
+ RTL_FLAG_MSTR_READY | RTL_FLAG_NO_APSS | RTL_FLAG_RUN | \
+ RTL_FLAG_APSS_NOT_INITD)
-#define CENTAUR_DATA_RTL_FLAGS (RTL_FLAG_MSTR | RTL_FLAG_NOTMSTR | RTL_FLAG_OBS | \
- RTL_FLAG_ACTIVE | RTL_FLAG_MSTR_READY | RTL_FLAG_NO_APSS | \
- RTL_FLAG_RUN | RTL_FLAG_APSS_NOT_INITD)
+#define MEMORY_DATA_RTL_FLAGS (RTL_FLAG_MSTR | RTL_FLAG_NOTMSTR | RTL_FLAG_OBS | \
+ RTL_FLAG_ACTIVE | RTL_FLAG_MSTR_READY | RTL_FLAG_NO_APSS | \
+ RTL_FLAG_RUN | RTL_FLAG_APSS_NOT_INITD)
// Tick Timer definitions
#define MICS_PER_TICK 250 // Number of micro-seconds per tick
diff --git a/src/occ_405/rtls/rtls_tables.c b/src/occ_405/rtls/rtls_tables.c
index 69c6219..9d63762 100755
--- a/src/occ_405/rtls/rtls_tables.c
+++ b/src/occ_405/rtls/rtls_tables.c
@@ -33,6 +33,7 @@
#include <centaur_data.h>
#include <centaur_control.h>
#include "amec_master_smh.h"
+#include "dimm.h"
//flags for task table
#define APSS_TASK_FLAGS RTL_FLAG_MSTR | RTL_FLAG_OBS | RTL_FLAG_ACTIVE | RTL_FLAG_MSTR_READY | RTL_FLAG_RUN
@@ -47,9 +48,9 @@
#define FLAGS_LOW_CORES_DATA RTL_FLAG_MSTR | RTL_FLAG_NOTMSTR | RTL_FLAG_OBS | RTL_FLAG_ACTIVE | RTL_FLAG_MSTR_READY | RTL_FLAG_NO_APSS | RTL_FLAG_RUN | RTL_FLAG_APSS_NOT_INITD
#define FLAGS_HIGH_CORES_DATA RTL_FLAG_MSTR | RTL_FLAG_NOTMSTR | RTL_FLAG_OBS | RTL_FLAG_ACTIVE | RTL_FLAG_MSTR_READY | RTL_FLAG_NO_APSS | RTL_FLAG_RUN | RTL_FLAG_APSS_NOT_INITD
-//Start out with centaur tasks not running.
-#define FLAGS_CENTAUR_DATA RTL_FLAG_NONE
-#define FLAGS_CENTAUR_CONTROL RTL_FLAG_NONE
+// Start out with memory tasks not running, then start during transition to observation in memory_init()
+#define FLAGS_MEMORY_DATA RTL_FLAG_NONE
+#define FLAGS_MEMORY_CONTROL RTL_FLAG_NONE
#define FLAGS_FAST_CORES_DATA RTL_FLAG_MSTR | RTL_FLAG_NOTMSTR | RTL_FLAG_OBS | RTL_FLAG_ACTIVE | RTL_FLAG_MSTR_READY | RTL_FLAG_NO_APSS | RTL_FLAG_RUN | RTL_FLAG_APSS_NOT_INITD
@@ -71,7 +72,6 @@
// TEMP/TODO: These are not yet implemented
#define FLAGS_GPU_SM
-#define FLAGS_DIMM_SM
#define FLAGS_MEM_DEADMAN
// Global tick sequences
@@ -121,8 +121,7 @@ task_t G_task_table[TASK_END] = {
// { FLAGS_CORE_DATA_CONTROL, task_core_data_control, NULL }, // TASK_ID_CORE_DATA_CONTROL
// TEMP -- NOT YET IMPLEMENTED
// { FLAGS_GPU_SM, task_gpu_sm, NULL }, // TASK_ID_GPU_SM
-// TEMP -- NOT YET IMPLEMENTED
-// { FLAGS_DIMM_SM, task_dimm_sm, NULL }, // TASK_ID_DIMM_SM
+ { FLAGS_MEMORY_DATA, task_dimm_sm, NULL }, // TASK_ID_DIMM_SM
// TEMP -- NOT YET IMPLEMENTED
// { FLAGS_MEM_DEADMAN, task_mem_deadman, NULL }, // TASK_ID_MEM_DEADMAN
};
@@ -130,7 +129,7 @@ task_t G_task_table[TASK_END] = {
const uint8_t G_tick0_seq[] = {
TASK_ID_APSS_START,
TASK_ID_CORE_DATA_LOW,
- //TASK_ID_DIMM_SM,
+ TASK_ID_DIMM_SM,
TASK_ID_APSS_CONT,
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
@@ -169,7 +168,7 @@ const uint8_t G_tick1_seq[] = {
const uint8_t G_tick2_seq[] = {
TASK_ID_APSS_START,
TASK_ID_CORE_DATA_LOW,
- //TASK_ID_DIMM_SM,
+ TASK_ID_DIMM_SM,
TASK_ID_APSS_CONT,
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
@@ -207,7 +206,7 @@ const uint8_t G_tick3_seq[] = {
const uint8_t G_tick4_seq[] = {
TASK_ID_APSS_START,
TASK_ID_CORE_DATA_LOW,
- //TASK_ID_DIMM_SM,
+ TASK_ID_DIMM_SM,
TASK_ID_APSS_CONT,
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
@@ -246,7 +245,7 @@ const uint8_t G_tick5_seq[] = {
const uint8_t G_tick6_seq[] = {
TASK_ID_APSS_START,
TASK_ID_CORE_DATA_LOW,
- //TASK_ID_DIMM_SM,
+ TASK_ID_DIMM_SM,
TASK_ID_APSS_CONT,
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
@@ -284,7 +283,7 @@ const uint8_t G_tick7_seq[] = {
const uint8_t G_tick8_seq[] = {
TASK_ID_APSS_START,
TASK_ID_CORE_DATA_LOW,
- //TASK_ID_DIMM_SM,
+ TASK_ID_DIMM_SM,
TASK_ID_APSS_CONT,
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
@@ -323,7 +322,7 @@ const uint8_t G_tick9_seq[] = {
const uint8_t G_tick10_seq[] = {
TASK_ID_APSS_START,
TASK_ID_CORE_DATA_LOW,
- //TASK_ID_DIMM_SM,
+ TASK_ID_DIMM_SM,
TASK_ID_APSS_CONT,
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
@@ -361,7 +360,7 @@ const uint8_t G_tick11_seq[] = {
const uint8_t G_tick12_seq[] = {
TASK_ID_APSS_START,
TASK_ID_CORE_DATA_LOW,
- //TASK_ID_DIMM_SM,
+ TASK_ID_DIMM_SM,
TASK_ID_APSS_CONT,
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
@@ -400,7 +399,7 @@ const uint8_t G_tick13_seq[] = {
const uint8_t G_tick14_seq[] = {
TASK_ID_APSS_START,
TASK_ID_CORE_DATA_LOW,
- //TASK_ID_DIMM_SM,
+ TASK_ID_DIMM_SM,
TASK_ID_APSS_CONT,
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
diff --git a/src/occ_405/state.c b/src/occ_405/state.c
index 8cb1124..b784fa4 100755
--- a/src/occ_405/state.c
+++ b/src/occ_405/state.c
@@ -40,6 +40,7 @@
//#include "heartbeat.h"
#include "scom.h"
#include <fir_data_collect.h>
+#include <dimm.h>
extern proc_gpsm_dcm_sync_occfw_t G_proc_dcm_sync_state;
extern bool G_mem_monitoring_allowed;
@@ -135,37 +136,8 @@ errlHndl_t SMGR_standby_to_observation()
l_error_logged = FALSE;
TRAC_IMP("SMGR: Standby to Observation Transition Started");
-// TEMP -- NOT SUPPORTED YET IN PHASE1
-/*
- //This flag is set if tmgt sends us at least one data set in the
- //mem config data packet. No data sets will be sent for centaur ec less than 2.0
- //due to an intermittent hw failure that can occur on those chips.
+ memory_init();
- if(G_mem_monitoring_allowed)
- {
- if(!rtl_task_is_runnable(TASK_ID_CENTAUR_DATA))
- {
-
- TRAC_INFO("SMGR_standby_to_observation: calling centaur_init()");
- centaur_init(); //no rc, handles errors internally
-
- //check if centaur_init resulted in a reset
- //since we don't have a return code from centaur_init.
- if(isSafeStateRequested())
- {
- TRAC_ERR("SMGR_standby_to_observation: OCC is being reset, centaur_init failed");
- }
- else
- {
- //initialization was successful.
- //Set task flags to allow centaur control task to run and
- //also to prevent us from doing initialization again.
- G_task_table[TASK_ID_CENTAUR_DATA].flags = CENTAUR_DATA_RTL_FLAGS;
- G_task_table[TASK_ID_CENTAUR_CONTROL].flags = CENTAUR_CONTROL_RTL_FLAGS;
- }
- }
- }
-*/
// Set the RTL Flags to indicate which tasks can run
// - Set OBSERVATION b/c we're in OBSERVATION State
rtl_clr_run_mask_deferred(RTL_FLAG_STANDBY);
diff --git a/src/occ_405/topfiles.mk b/src/occ_405/topfiles.mk
index c13d742..58aa999 100644
--- a/src/occ_405/topfiles.mk
+++ b/src/occ_405/topfiles.mk
@@ -47,6 +47,7 @@ TOP-C-SOURCES = amec/amec_data.c \
dcom/dcomMasterRx.c \
dcom/dcomSlaveRx.c \
dcom/dcomSlaveTx.c \
+ dimm/dimm.c \
errl/errl.c \
firdata/fir_data_collect.c \
homer.c \
diff --git a/src/occ_405/trac/trac.h b/src/occ_405/trac/trac.h
index dad0ad4..92fd9bf 100755
--- a/src/occ_405/trac/trac.h
+++ b/src/occ_405/trac/trac.h
@@ -287,6 +287,16 @@ extern void dumpHexString(const void *i_data, const unsigned int len, const char
#define CNFG_DBG_HEXDUMP(data, len, string)
#endif
+#ifdef DIMM_DEBUG
+ #define DIMM_DBG(frmt,args...) \
+ DBG_PRINT(frmt,##args)
+ #define DIMM_DBG_HEXDUMP(data, len, string) \
+ DEBUG_HEXDUMP(data, len, string)
+#else
+ #define DIMM_DBG(frmt,args...)
+ #define DIMM_DBG_HEXDUMP(data, len, string)
+#endif
+
#else // NO_TRAC_STRINGS
#define TRAC_ERR(frmt,args...)
@@ -307,6 +317,7 @@ extern void dumpHexString(const void *i_data, const unsigned int len, const char
#define SNSR_DBG(frmt,args...)
#define TMER_DBG(frmt,args...)
#define CNFG_DBG(frmt,args...)
+#define DIMM_DBG(frmt,args...)
#define MAIN_DBG_HEXDUMP(frmt,args...)
#define RTLS_DBG_HEXDUMP(frmt,args...)
@@ -322,6 +333,7 @@ extern void dumpHexString(const void *i_data, const unsigned int len, const char
#define SNSR_DBG_HEXDUMP(frmt,args...)
#define TMER_DBG_HEXDUMP(frmt,args...)
#define CNFG_DBG_HEXDUMP(frmt,args...)
+#define DIMM_DBG_HEXDUMP(frmt,args...)
#endif
diff --git a/src/occ_gpe1/gpe1.h b/src/occ_gpe1/gpe1.h
new file mode 100755
index 0000000..af26829
--- /dev/null
+++ b/src/occ_gpe1/gpe1.h
@@ -0,0 +1,76 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/gpe/gpe1.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 _GPE1_H
+#define _GPE1_H
+
+#include "gpe_export.h"
+
+
+// I2C SCOM Addresses:
+// (There are unique constants/addresses per engine, but to make the calls generic,
+// these constants are defined instead of using the base constants)
+#define PIB_BASE 0x000A0000
+// Engine B 0x00A0000
+// Engine C 0x00A1000
+// Engine D 0x00A2000
+// Engine E 0x00A3000
+#define SCOM_ENGINE_OFFSET(engine) (engine << 12)
+#define I2C_FIFO1_REG_READ 0x000A0004
+#define I2C_COMMAND_REG 0x000A0005
+#define I2C_MODE_REG 0x000A0006
+#define I2C_INTERRUPT_MASK_REG 0x000A0008
+#define I2C_STATUS_REG 0x000A000B // read
+#define I2C_IMM_RESET_I2C 0x000A000B // write
+#define I2C_BUSY_REGISTER 0x000A000E
+#define I2C_FIFO4_REG_READ 0x000A0012
+
+
+// I2C Status Reigster masks
+#define STATUS_ERROR_MASK 0xFE80330000000000
+#define STATUS_ERROR_OR_COMPLETE_MASK 0xFF80330000000000
+#define STATUS_COMPLETE_MASK 0x0100000000000000
+#define PEEK_ERROR_MASK 0x00000000FC000000
+#define PEEK_MORE_DATA 0x0000000002000000
+
+
+// Debug trace
+#ifdef GPE1_DEBUG
+ #define GPE1_DIMM_DBG(frmt,args...) \
+ PK_TRACE(frmt,##args)
+ #define GPE1_DIMM_DBG_HEXDUMP(data, len, string) \
+ PK_TRACE_BIN(data, len, string)
+#else
+ #define GPE1_DIMM_DBG(frmt,args...)
+ #define GPE1_DIMM_DBG_HEXDUMP(data, len, string)
+#endif
+
+
+void gpe_set_ffdc(GpeErrorStruct *o_error, uint32_t i_addr, uint32_t i_rc, uint64_t i_ffdc);
+
+void gpe_dimm_sm(ipc_msg_t* cmd, void* arg);
+
+
+#endif //_GPE1_H
diff --git a/src/occ_gpe1/gpe1_dimm.h b/src/occ_gpe1/gpe1_dimm.h
new file mode 100755
index 0000000..c3249c6
--- /dev/null
+++ b/src/occ_gpe1/gpe1_dimm.h
@@ -0,0 +1,60 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/gpe/gpe1_dimm.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 _GPE1_DIMM_H
+#define _GPE1_DIMM_H
+
+#include "gpe_export.h"
+
+#define PIB_BASE 0x000A0000
+// Engine B 0x00A0000
+// Engine C 0x00A1000
+// Engine D 0x00A2000
+// Engine E 0x00A3000
+#define I2C_FIFO1_REG_READ 0x000A0004
+#define I2C_COMMAND_REG 0x000A0005
+#define I2C_MODE_REG 0x000A0006
+#define I2C_INTERRUPT_MASK_REG 0x000A0008
+#define I2C_STATUS_REG 0x000A000B // read
+#define I2C_IMM_RESET_I2C 0x000A000B // write
+#define I2C_BUSY_REGISTER 0x000A000E
+#define I2C_FIFO4_REG_READ 0x000A0012
+
+#define SCOM_ENGINE_OFFSET(engine) (engine << 12)
+
+// I2C Status Reigster masks
+#define STATUS_ERROR_MASK 0xFE80330000000000
+#define STATUS_ERROR_OR_COMPLETE_MASK 0xFF80330000000000
+#define STATUS_COMPLETE_MASK 0x0100000000000000
+#define PEEK_ERROR_MASK 0x00000000FC000000
+#define PEEK_MORE_DATA 0x0000000002000000
+
+
+void dimm_set_ffdc(GpeErrorStruct *o_error, uint32_t i_addr, uint32_t i_rc, uint64_t i_ffdc);
+
+void gpe_dimm_sm(ipc_msg_t* cmd, void* arg);
+
+
+#endif //_GPE1_DIMM_H
diff --git a/src/occ_gpe1/gpe1_dimm_read.c b/src/occ_gpe1/gpe1_dimm_read.c
new file mode 100644
index 0000000..be19506
--- /dev/null
+++ b/src/occ_gpe1/gpe1_dimm_read.c
@@ -0,0 +1,511 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_gpe1/gpe1_dimm_read.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 */
+
+/// \file gpe1_dimm_read.c
+/// \brief Functions to handle reading the DIMM temperatures
+///
+
+//#define GPE1_DEBUG
+#include "pk.h"
+#include "ipc_api.h"
+#include "ppe42_scom.h"
+#include "ipc_async_cmd.h"
+#include "gpe1.h"
+#include "gpe1_dimm.h"
+
+
+void dimm_write_int_mask(ipc_msg_t* cmd, void* arg);
+void dimm_write_mode(ipc_msg_t* cmd, void* arg);
+void dimm_write_ts_addr(ipc_msg_t* cmd, void* arg);
+void dimm_initiate_read(ipc_msg_t* cmd, void* arg);
+void dimm_read_temp(ipc_msg_t* cmd, void* arg);
+// from gpe1_dimm_reset.c
+void dimm_reset_master(ipc_msg_t* cmd, void* arg);
+void dimm_reset_slave(ipc_msg_t* cmd, void* arg);
+void dimm_reset_slave_status(ipc_msg_t* cmd, void* arg);
+
+
+/*
+ * Function Specification
+ *
+ * Name: gpe_set_ffdc
+ *
+ * Description: Fills up the error struct with the given data.
+ *
+ * End Function Specification
+ */
+void gpe_set_ffdc(GpeErrorStruct *o_error, uint32_t i_addr, uint32_t i_rc, uint64_t i_ffdc)
+{
+
+ o_error->addr = i_addr;
+ //Return codes defined in gpe_err.h
+ o_error->rc = i_rc;
+ o_error->ffdc = i_ffdc;
+}
+
+
+/*
+ * Function Specifications:
+ *
+ * Name: gpe_dimm_sm
+ *
+ * Description: DIMM I2C State Machine handler in the GPE
+ *
+ * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct
+ *
+ * Outputs: error: sets rc, address, and ffdc in the cmd_data's
+ * GpeErrorStruct
+ *
+ * End Function Specification
+ */
+void gpe_dimm_sm(ipc_msg_t* cmd, void* arg)
+{
+ // Note: arg was set to 0 in ipc func table (ipc_func_tables.c), so don't use it.
+ // the ipc arguments passed through the ipc_msg_t structure, has a pointer
+ // to the G_gpe_start_pwr_meas_read_args struct.
+ int rc;
+ ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd;
+ dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data;
+
+ // clear error
+ args->error.error = 0;
+ args->error.ffdc = 0;
+
+ switch(args->state)
+ {
+ case DIMM_STATE_INIT:
+ dimm_write_int_mask(cmd, arg);
+ break;
+
+ // Read DIMM Temperature States
+
+ case DIMM_STATE_WRITE_MODE:
+ dimm_write_mode(cmd, arg);
+ break;
+
+ case DIMM_STATE_WRITE_ADDR:
+ dimm_write_ts_addr(cmd, arg);
+ break;
+
+ case DIMM_STATE_INITIATE_READ:
+ dimm_initiate_read(cmd, arg);
+ break;
+
+ case DIMM_STATE_READ_TEMP:
+ dimm_read_temp(cmd, arg);
+ break;
+
+ // I2C Reset States
+
+ case DIMM_STATE_RESET_MASTER:
+ dimm_reset_master(cmd, arg);
+ break;
+
+ case DIMM_STATE_RESET_SLAVE_P0:
+ case DIMM_STATE_RESET_SLAVE_P1:
+ dimm_reset_slave(cmd, arg);
+ break;
+
+ case DIMM_STATE_RESET_SLAVE_P0_COMPLETE:
+ case DIMM_STATE_RESET_SLAVE_P1_COMPLETE:
+ dimm_reset_slave_status(cmd, arg);
+ break;
+
+ default:
+ PK_TRACE("gpe_dimm_sm: Invalid state (0x%02X) received!", args->state);
+ args->error.rc = 0;
+ gpe_set_ffdc(&(args->error), 0, GPE_RC_INVALID_STATE, args->state);
+ break;
+ }
+
+ // Send back IPC response of success (IPC operation itself succeeded)
+ // (if any operation failed, the error (rc/ffdc) will be non-zero
+ // and can be handled by the 405)
+ rc = ipc_send_rsp(cmd, IPC_RC_SUCCESS);
+ if(rc)
+ {
+ PK_TRACE("gpe_dimm_sm: Failed to send response back. Halting GPE1", rc);
+ gpe_set_ffdc(&(args->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc);
+ pk_halt();
+ }
+
+} // end gpe_dimm_sm()
+
+
+/*
+ * Function Specifications:
+ *
+ * Name: dimm_write_int_mask
+ *
+ * Description: Write the I2C interrupt mask and read I2C status register
+ *
+ * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct
+ *
+ * Outputs: error: sets rc, address, and ffdc in the cmd_data's
+ * GpeErrorStruct
+ *
+ * End Function Specification
+ */
+void dimm_write_int_mask(ipc_msg_t* cmd, void* arg)
+{
+ int rc;
+ uint32_t scomAddr;
+ uint64_t regValue; // a pointer to hold the putscom_abs register value
+ ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd;
+ dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data;
+
+ scomAddr = I2C_INTERRUPT_MASK_REG | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ // Enable the following bit in the interrupt mask:
+ // invalid command, LBUS parity, back end overrun, back end access,
+ // arbitration lost, nack received, data request, command complete,
+ // stop, i2c busy
+ regValue = 0x0000FFC000000000;
+ rc = putscom_abs(scomAddr, regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_write_int_mask: I2C_INTERRUPT_MASK_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_write_int_mask: putscom(0x%08X,0x%08X%08X) SUCCESS - INT MASK",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+ }
+
+ // READ I2C STATUS REGISTER
+ scomAddr = I2C_STATUS_REG | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ rc = getscom_abs(scomAddr, &regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_write_int_mask: I2C_STATUS_REG getscom 0x%08X FAILED. rc = 0x%08x - STATUS",
+ scomAddr, rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_GET_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_write_int_mask: getscom(0x%08X) returned 0x%08X%08X) - STATUS #1",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+ // max_num_of_ports (bits 9:15)
+ args->maxPorts = (regValue >> 48) & 0x7F;
+ PK_TRACE("dimm_write_int_mask: maxPorts = %d", args->maxPorts);
+ }
+
+} // end dimm_write_int_mask()
+
+
+/*
+ * Function Specifications:
+ *
+ * Name: dimm_write_mode
+ *
+ * Description: Write the I2C mode register (set speed and port)
+ *
+ * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct
+ *
+ * Outputs: error: sets rc, address, and ffdc in the cmd_data's
+ * GpeErrorStruct
+ *
+ * End Function Specification
+ */
+
+void dimm_write_mode(ipc_msg_t* cmd, void* arg)
+{
+ // Note: arg was set to 0 in ipc func table (ipc_func_tables.c), so don't use it.
+ // the ipc arguments passed through the ipc_msg_t structure, has a pointer
+ // to the G_gpe_start_pwr_meas_read_args struct.
+
+ int rc;
+ uint32_t scomAddr;
+ uint64_t regValue; // a pointer to hold the putscom_abs register value
+ ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd;
+ dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data;
+
+ // MODE_REGISTER
+ scomAddr = I2C_MODE_REG | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ regValue = 0x0177000000000000;
+ if ((args->i2cPort > 0) && (args->i2cPort < 6))
+ {
+ regValue |= ((uint64_t)args->i2cPort << 42);
+ }
+ rc = putscom_abs(scomAddr, regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_write_mode: I2C_MODE_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_write_mode: putscom(0x%08X,0x%08X%08X) SUCCESS - MODE",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+ }
+
+} // end dimm_write_mode()
+
+
+/*
+ * Function Specifications:
+ *
+ * Name: dimm_write_ts_addr
+ *
+ * Description: Write the Temperature Sensor address to I2C
+ *
+ * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct
+ *
+ * Outputs: error: sets rc, address, and ffdc in the cmd_data's
+ * GpeErrorStruct
+ *
+ * End Function Specification
+ */
+void dimm_write_ts_addr(ipc_msg_t* cmd, void* arg)
+{
+ int rc;
+ uint32_t scomAddr;
+ uint64_t regValue; // a pointer to hold the putscom_abs register value
+ ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd;
+ dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data;
+
+ // Write I2C command register with a 1 byte write
+ scomAddr = I2C_COMMAND_REG | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ // start+address + slave_address, rw=0=write, length=1, i2c address
+ regValue = 0xC000000100000000 | ((uint64_t)args->i2cAddr << 48);
+ rc = putscom_abs(scomAddr, regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_write_ts_addr: I2C_COMMAND_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_write_ts_addr: putscom(0x%08X,0x%08X%08X) SUCCESS - COMMAND (write)",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+
+ // Write the Temperature Sensor address to the FIFO register
+ scomAddr = I2C_FIFO1_REG_READ | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ // 0x05 = temperature value
+ regValue = 0x0500000000000000;
+ rc = putscom_abs(scomAddr, regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_write_ts_addr: I2C_FIFO_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_write_ts_addr: putscom(0x%08X,0x%08X%08X) SUCCESS - FIFO",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+ }
+ }
+
+} // end dimm_write_ts_addr()
+
+
+/*
+ * Function Specifications:
+ *
+ * Name: dimm_initiate_read
+ *
+ * Description: Initiate the read of the temperature sensor
+ *
+ * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct
+ *
+ * Outputs: error: sets rc, address, and ffdc in the cmd_data's
+ * GpeErrorStruct
+ *
+ * End Function Specification
+ */
+void dimm_initiate_read(ipc_msg_t* cmd, void* arg)
+{
+ int rc;
+ uint32_t scomAddr;
+ uint64_t regValue; // a pointer to hold the putscom_abs register value
+ ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd;
+ dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data;
+
+ // Default the rc to NOT_COMPLETE (meaning the read was not initiated)
+ args->error.rc = GPE_RC_NOT_COMPLETE;
+
+ // Read the I2c Status Register to ensure the TS address was written successfully
+ scomAddr = I2C_STATUS_REG | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ rc = getscom_abs(scomAddr, &regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_initiate_read: I2C_STATUS_REG getscom 0x%08X FAILED. rc = 0x%08x",
+ scomAddr, rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_GET_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_initiate_read: getscom(0x%08X) returned 0x%08X%08X - STATUS",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+
+ if ((regValue & STATUS_ERROR_OR_COMPLETE_MASK) == STATUS_COMPLETE_MASK)
+ {
+ // Status register indicates no errors and last command completed.
+ // Write the I2C command register with a 2 byte read request
+ scomAddr = I2C_COMMAND_REG | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ // start+address+stop + slave_address, rw=1=read, length=2
+ regValue = 0xD001000200000000;
+ regValue |= ((uint64_t)args->i2cAddr << 48);
+ rc = putscom_abs(scomAddr, regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_initiate_read: I2C_COMMAND_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+ else
+ {
+ // The read command has been started, return success
+ GPE1_DIMM_DBG("dimm_initiate_read: putscom(0x%08X,0x%08X%08X) SUCCESS - COMMAND (read)",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+ args->error.error = 0;
+ args->error.rc = GPE_RC_SUCCESS;
+ args->error.ffdc = 0;
+ }
+ }
+ else
+ {
+ if ((regValue & STATUS_ERROR_OR_COMPLETE_MASK) != 0)
+ {
+ // I2C error was found
+ PK_TRACE("dimm_initiate_read: Error in status register: 0x%08X%08X",
+ WORD_HIGH(regValue), WORD_LOW(regValue));
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_I2C_ERROR, regValue);
+ }
+ else
+ {
+ // Last command (write TS address) has not completed yet
+ PK_TRACE("dimm_initiate_read: last command not complete yet...");
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_NOT_COMPLETE, regValue);
+ }
+ // else, not complete yet
+ }
+ }
+
+} // end dimm_initiate_read()
+
+
+/*
+ * Function Specifications:
+ *
+ * Name: dimm_read_temp
+ *
+ * Description: Read the temperature sensor value
+ *
+ * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct
+ *
+ * Outputs: error: sets rc, address, and ffdc in the cmd_data's
+ * GpeErrorStruct
+ *
+ * End Function Specification
+ */
+void dimm_read_temp(ipc_msg_t* cmd, void* arg)
+{
+ int rc;
+ uint32_t scomAddr;
+ uint64_t regValue; // a pointer to hold the putscom_abs register value
+ ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd;
+ dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data;
+
+ // Default the rc to NOT_COMPLETE (meaning the read has not completed)
+ args->error.rc = GPE_RC_NOT_COMPLETE;
+
+ // Read the I2C status register
+ scomAddr = I2C_STATUS_REG | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ rc = getscom_abs(scomAddr, &regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_read_temp: I2C_STATUS_REG getscom 0x%08X FAILED. rc = 0x%08x - STATUS #1",
+ scomAddr, rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_GET_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_read_temp: getscom(0x%08X) returned 0x%08X%08X) - STATUS #1",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+
+ uint8_t fifoLength = (regValue >> 32) & 0xFF;
+ if ((regValue & STATUS_ERROR_MASK) != 0)
+ {
+ // I2C error was found
+ PK_TRACE("dimm_read_temp: Error in status register: 0x%08X%08X",
+ WORD_HIGH(regValue), WORD_LOW(regValue));
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_I2C_ERROR, regValue);
+ }
+ else
+ {
+ // Need to wait until both bytes are available
+ if (fifoLength >= 2)
+ {
+ // Read the sensor value from the FIFO4 register
+ scomAddr = I2C_FIFO4_REG_READ | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ rc = getscom_abs(scomAddr, &regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_read_temp: I2C_FIFO4_REG getscom 0x%08X FAILED. rc = 0x%08x",
+ scomAddr, rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_GET_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_read_temp: getscom(0x%08X) returned 0x%08X%08X) - FIFO4",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+ // Temperature is in bits 4-11
+ args->temp = (regValue >> 52) & 0xFF;
+ args->error.error = 0;
+ args->error.rc = GPE_RC_SUCCESS;
+ args->error.ffdc = 0;
+ PK_TRACE("dimm_read_temp: DIMM%04X temperature=%dC",
+ (args->i2cPort<<8)|args->dimm, args->temp);
+
+ // Check for operation complete bit
+ // (operation complete bit will not get set until all
+ // data has been read from the FIFO.)
+ if (regValue & PEEK_ERROR_MASK)
+ {
+ // I2C error was found
+ PK_TRACE("dimm_read_temp: Error in FIFO4 peek data: 0x%08X%08X",
+ WORD_HIGH(regValue), WORD_LOW(regValue));
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_I2C_ERROR, regValue);
+ }
+ else if (regValue & PEEK_MORE_DATA)
+ {
+ // The data_request bit is non-zero, but no more data is needed!
+ PK_TRACE("dimm_read_temp: Got data, but more data needs access??");
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_NOT_COMPLETE, regValue);
+ }
+ }
+ }
+ // else, all data not available yet (NOT_COMPLETE)
+ }
+ }
+
+} // end dimm_read_temp()
+
+
diff --git a/src/occ_gpe1/gpe1_dimm_reset.c b/src/occ_gpe1/gpe1_dimm_reset.c
new file mode 100644
index 0000000..9963eec
--- /dev/null
+++ b/src/occ_gpe1/gpe1_dimm_reset.c
@@ -0,0 +1,223 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_gpe1/gpe1_dimm_reset.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 */
+
+/// \file gpe1_dimm_reset.c
+/// \brief Functions to handle resetting the I2C engine
+///
+
+//#define GPE1_DEBUG
+#include "pk.h"
+#include "ipc_api.h"
+#include "ppe42_scom.h"
+#include "ipc_async_cmd.h"
+#include "gpe1.h"
+#include "gpe1_dimm.h"
+
+
+/*
+ * Function Specifications:
+ *
+ * Name: dimm_reset_master
+ *
+ * Description: Reset the I2C master
+ *
+ * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct
+ *
+ * Outputs: error: sets rc, address, and ffdc in the cmd_data's
+ * GpeErrorStruct
+ *
+ * End Function Specification
+ */
+void dimm_reset_master(ipc_msg_t* cmd, void* arg)
+{
+ // Note: arg was set to 0 in ipc func table (ipc_func_tables.c), so don't use it.
+ // the ipc arguments passed through the ipc_msg_t structure, has a pointer
+ // to the G_gpe_start_pwr_meas_read_args struct.
+
+ int rc;
+ uint32_t scomAddr;
+ uint64_t regValue; // a pointer to hold the putscom_abs register value
+ ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd;
+ dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data;
+
+ // Reset I2C Master
+ scomAddr = I2C_IMM_RESET_I2C | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ regValue = 0x0000000000000000;
+ rc = putscom_abs(scomAddr, regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_reset_master: I2C_IMM_RESET_I2C putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_reset_master: putscom(0x%08X,0x%08X%08X) SUCCESS - IMM_RESET_I2C",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+ }
+
+ // Force reset of Port_busy_register
+ scomAddr = I2C_BUSY_REGISTER | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ regValue = 0x8000000000000000;
+ rc = putscom_abs(scomAddr, regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_reset_master: I2C_BUSY_REGISTER putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_reset_master: putscom(0x%08X,0x%08X%08X) SUCCESS - I2C_BUSY_REGISTER",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+ }
+
+} // end dimm_reset_master()
+
+
+/*
+ * Function Specifications:
+ *
+ * Name: dimm_reset_slave
+ *
+ * Description: Start reset of I2C slave
+ *
+ * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct
+ *
+ * Outputs: error: sets rc, address, and ffdc in the cmd_data's
+ * GpeErrorStruct
+ *
+ * End Function Specification
+ */
+
+void dimm_reset_slave(ipc_msg_t* cmd, void* arg)
+{
+ int rc;
+ uint32_t scomAddr;
+ uint64_t regValue; // a pointer to hold the putscom_abs register value
+ ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd;
+ dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data;
+
+ // Write I2C mode register with the speed/port
+ scomAddr = I2C_MODE_REG | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ regValue = 0x0177000000000000;
+ if ((args->i2cPort > 0) && (args->i2cPort < 6))
+ {
+ regValue |= ((uint64_t)args->i2cPort << 42);
+ }
+ rc = putscom_abs(scomAddr, regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_reset_slave: I2C_MODE_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_reset_slave: putscom(0x%08X,0x%08X%08X) SUCCESS - MODE",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+
+ // Force a stop-condition to the I2C slave
+ scomAddr = I2C_COMMAND_REG | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ // stop bit
+ regValue = 0x1000000000000000;
+ rc = putscom_abs(scomAddr, regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_reset_slave: I2C_COMMAND_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_reset_slave: putscom(0x%08X,0x%08X%08X) SUCCESS - COMMAND (stop)",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+ }
+ }
+
+} // end dimm_reset_slave()
+
+
+/*
+ * Function Specifications:
+ *
+ * Name: dimm_reset_slave_status
+ *
+ * Description: Read I2C status register to ensure slave has been reset
+ *
+ * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct
+ *
+ * Outputs: error: sets rc, address, and ffdc in the cmd_data's
+ * GpeErrorStruct
+ *
+ * End Function Specification
+ */
+void dimm_reset_slave_status(ipc_msg_t* cmd, void* arg)
+{
+ int rc;
+ uint32_t scomAddr;
+ uint64_t regValue; // a pointer to hold the putscom_abs register value
+ ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd;
+ dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data;
+
+ // Read I2C status register
+ scomAddr = I2C_STATUS_REG | SCOM_ENGINE_OFFSET(args->i2cEngine);
+ rc = getscom_abs(scomAddr, &regValue);
+ if(rc)
+ {
+ PK_TRACE("dimm_reset_slave_status: I2C_STATUS_REG getscom 0x%08X FAILED. rc = 0x%08x - STATUS #1",
+ scomAddr, rc);
+ gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_GET_FAILED, rc);
+ }
+ else
+ {
+ GPE1_DIMM_DBG("dimm_reset_slave_status: getscom(0x%08X) returned 0x%08X%08X) - STATUS #1",
+ scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue));
+
+ // Wait until command complete is set
+ if (regValue & STATUS_COMPLETE_MASK)
+ {
+ // Reset completed
+ args->error.rc = GPE_RC_SUCCESS;
+ PK_TRACE("dimm_reset_slave_status: I2C Slave Port %d Reset completed", args->i2cPort);
+
+ if ((regValue & STATUS_ERROR_OR_COMPLETE_MASK) != STATUS_COMPLETE_MASK)
+ {
+ // I2C errors found
+ PK_TRACE("dimm_reset_slave_status: I2C errors in status register: %08X%08X",
+ WORD_HIGH(regValue), WORD_LOW(regValue));
+ // Continue with other slave resets and may trigger another reset...
+ }
+ }
+ else
+ {
+ // reset not complete yet...
+ args->error.rc = GPE_RC_NOT_COMPLETE;
+ }
+ }
+
+} // end dimm_reset_slave_status()
+
+
diff --git a/src/occ_gpe1/gpe1_main.c b/src/occ_gpe1/gpe1_main.c
index e81869e..88f3be8 100644
--- a/src/occ_gpe1/gpe1_main.c
+++ b/src/occ_gpe1/gpe1_main.c
@@ -1,7 +1,7 @@
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
-/* $Source: src/occ_gpe0/gpe0_main.c $ */
+/* $Source: src/occ_gpe1/gpe1_main.c $ */
/* */
/* OpenPOWER OnChipController Project */
/* */
@@ -31,12 +31,12 @@
#include "pk.h"
#include "ipc_api.h"
-#include "ipc_ping.h"
#define KERNEL_STACK_SIZE 256
uint8_t G_kernel_stack[KERNEL_STACK_SIZE];
+
// The main function is called by the boot code (after initializing some
// registers)
int main(int argc, char **argv)
@@ -51,7 +51,7 @@ int main(int argc, char **argv)
PK_TRACE("Kernel init completed");
- // Disable IPC's and register the IPC interrupt handler
+ // Disable IPC's and register the IPC interrupt handler
rc = ipc_init();
if(rc)
{
diff --git a/src/occ_gpe1/ipc_func_tables.c b/src/occ_gpe1/ipc_func_tables.c
index 1dfa02e..3c34920 100644
--- a/src/occ_gpe1/ipc_func_tables.c
+++ b/src/occ_gpe1/ipc_func_tables.c
@@ -1,4 +1,6 @@
#include "ipc_api.h"
+#include "gpe1_dimm.h"
+
// Function table for multi target (common) functions
IPC_MT_FUNC_TABLE_START
@@ -14,7 +16,7 @@ IPC_MT_FUNC_TABLE_END
// Function table for single target (processor-specific) functions
IPC_ST_FUNC_TABLE_START
-IPC_HANDLER_DEFAULT // 0
+IPC_HANDLER(gpe_dimm_sm, 0) // 0 - IPC_ST_DIMM_SM_FUNCID
IPC_HANDLER_DEFAULT // 1
IPC_HANDLER_DEFAULT // 2
IPC_HANDLER_DEFAULT // 3
diff --git a/src/occ_gpe1/topfiles.mk b/src/occ_gpe1/topfiles.mk
index 698d29f..0b8ca4b 100644
--- a/src/occ_gpe1/topfiles.mk
+++ b/src/occ_gpe1/topfiles.mk
@@ -1,4 +1,4 @@
-TOP-C-SOURCES = gpe1_main.c pk_app_irq_table.c ipc_func_tables.c
+TOP-C-SOURCES = gpe1_main.c gpe1_dimm_read.c gpe1_dimm_reset.c pk_app_irq_table.c ipc_func_tables.c
TOP-S-SOURCES =
TOP_OBJECTS = $(TOP-C-SOURCES:.c=.o) $(TOP-S-SOURCES:.S=.o)
OpenPOWER on IntegriCloud