diff options
author | Chris Cain <cjcain@us.ibm.com> | 2015-11-19 12:27:03 -0600 |
---|---|---|
committer | William A. Bryan <wilbryan@us.ibm.com> | 2016-01-27 16:27:07 -0600 |
commit | 1cdc7f74cf7303b2d2e7e172b0e269928def09de (patch) | |
tree | bc88add88943f8389626a04c5219d0efc3d08f17 /src | |
parent | 476a284b52f50c1d0f5a8fc637cc28a22c714185 (diff) | |
download | talos-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')
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, ®Value); + 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, ®Value); + 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, ®Value); + 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, ®Value); + 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, ®Value); + 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) |