blob: 757f701715342754875cb0ff3b26c385ab481311 [file] [log] [blame]
From 3f630837040bae961612214307d2903e65af9e5d Mon Sep 17 00:00:00 2001
From: Mike Baiocchi <baiocchi@us.ibm.com>
Date: Thu, 2 Apr 2015 13:42:00 -0500
Subject: [PATCH 05/10] Fix I2C Reset to resolve I2C Bus Arbitration Lost
Errors
This commit fixes 2 bugs where the full "Force Reset and Unlock"
I2C reset procedure used to both avoid and recover from I2C Bus
Arbitration Lost errors was not being performed correctly on any
ports but port 0.
Change-Id: Ie967d81917e9b942d5cb516856075ebdb5029487
CQ: SW297864
(cherry picked from commit 01ee7107170c867d25af2485b75307e3bfa87339)
---
src/include/usr/i2c/i2creasoncodes.H | 1 +
src/usr/i2c/i2c.C | 182 ++++++++++++++++++++++++-----------
src/usr/i2c/i2c.H | 4 +-
3 files changed, 130 insertions(+), 57 deletions(-)
diff --git a/src/include/usr/i2c/i2creasoncodes.H b/src/include/usr/i2c/i2creasoncodes.H
index a63e8d5..454ef15 100644
--- a/src/include/usr/i2c/i2creasoncodes.H
+++ b/src/include/usr/i2c/i2creasoncodes.H
@@ -58,6 +58,7 @@ enum i2cModuleId
I2C_SETUP_MASTERS = 0x08,
I2C_SEND_SLAVE_STOP = 0x09,
I2C_PROCESS_ACTIVE_MASTERS = 0x0A,
+ I2C_FORCE_RESET_AND_UNLOCK = 0x0B,
};
diff --git a/src/usr/i2c/i2c.C b/src/usr/i2c/i2c.C
index bc4bb7b..ee7e5e3 100755
--- a/src/usr/i2c/i2c.C
+++ b/src/usr/i2c/i2c.C
@@ -1925,6 +1925,11 @@ errlHndl_t i2cForceResetAndUnlock( TARGETING::Target * i_target,
{
errlHndl_t err = NULL;
+ mode_reg_t mode;
+ uint64_t l_speed = I2C_BUS_SPEED_FROM_MRW;
+
+ // I2C Bus Speed Array
+ TARGETING::ATTR_I2C_BUS_SPEED_ARRAY_type speed_array;
TRACDCOMP( g_trac_i2c,
ENTER_MRK"i2cForceResetAndUnlock()" );
@@ -1932,62 +1937,122 @@ errlHndl_t i2cForceResetAndUnlock( TARGETING::Target * i_target,
do
{
- // enable diagnostic mode
- // set bit in mode register
- mode_reg_t diagnostic;
-
- diagnostic.diag_mode = 0x1;
-
- err = i2cRegisterOp( DeviceFW::WRITE,
- i_target,
- &diagnostic.value,
- I2C_REG_MODE,
- i_args );
-
- if( err )
+ // Get I2C Bus Speed Array attribute. It will be used to determine
+ // which engine/port combinations have devices on them
+ if ( !( i_target->tryGetAttr<TARGETING::ATTR_I2C_BUS_SPEED_ARRAY>
+ (speed_array) ) )
{
TRACFCOMP( g_trac_i2c,
- ERR_MRK"I2C Enable Diagnostic mode Failed!!" );
+ ERR_MRK"i2cForceResetAndUnlock() - Cannot find "
+ "ATTR_I2C_BUS_SPEED_ARRAY needed for operation");
+ /*@
+ * @errortype
+ * @reasoncode I2C_ATTRIBUTE_NOT_FOUND
+ * @severity ERRORLOG_SEV_UNRECOVERABLE
+ * @moduleid I2C_FORCE_RESET_AND_UNLOCK
+ * @userdata1 Target for the attribute
+ * @userdata2 <UNUSED>
+ * @devdesc ATTR_I2C_BUS_SPEED_ARRAY not found
+ * @custdesc I2C configuration data missing
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_FORCE_RESET_AND_UNLOCK,
+ I2C_ATTRIBUTE_NOT_FOUND,
+ TARGETING::get_huid(i_target),
+ 0x0,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( I2C_COMP_NAME, 256);
+
break;
}
+ // Need to send slave stop to all ports with a device on the engine
+ for( uint32_t port = 0; port < P8_MASTER_PORTS; port++ )
+ {
- //toggle clock line
- err = i2cToggleClockLine( i_target,
- i_args );
+ // Only send stop to a port if there are devices on it
+ l_speed = speed_array[i_args.engine][port];
+ if ( l_speed == 0 )
+ {
+ continue;
+ }
- if( err )
- {
- break;
- }
+ TRACUCOMP( g_trac_i2c,
+ INFO_MRK"i2cForceResetAndUnlock() - Performing op on "
+ "engine=%d, port=%d",
+ i_args.engine, port);
- //manually send stop signal
- err = i2cSendStopSignal( i_target,
- i_args );
+ // Clear mode register
+ mode.value = 0x0ull;
- if( err )
- {
- break;
- }
+ // set port in mode register
+ mode.port_num = port;
- //disable diagnostic mode
- //set bit in mode register
- diagnostic.diag_mode = 0x0;
+ // enable diagnostic mode in mode register
+ mode.diag_mode = 0x1;
- err = i2cRegisterOp( DeviceFW::WRITE,
- i_target,
- &diagnostic.value,
- I2C_REG_MODE,
- i_args );
+ err = i2cRegisterOp( DeviceFW::WRITE,
+ i_target,
+ &mode.value,
+ I2C_REG_MODE,
+ i_args );
+ if( err )
+ {
+ TRACFCOMP( g_trac_i2c,
+ ERR_MRK"I2C Enable Diagnostic mode Failed!!" );
- if( err )
- {
- TRACFCOMP( g_trac_i2c,
- ERR_MRK"I2C disable Diagnostic mode Failed!!" );
- break;
- }
+ // We still need to reset the other ports on this I2C engine
+ errlCommit( err, I2C_COMP_ID );
+ continue;
+ }
+
+
+ //toggle clock line
+ err = i2cToggleClockLine( i_target,
+ i_args );
+
+ if( err )
+ {
+ // We still need to reset the other ports on this I2C engine
+ errlCommit( err, I2C_COMP_ID );
+ continue;
+ }
+
+ //manually send stop signal
+ err = i2cSendStopSignal( i_target,
+ i_args );
+
+ if( err )
+ {
+ // We still need to reset the other ports on this I2C engine
+ errlCommit( err, I2C_COMP_ID );
+ continue;
+ }
+
+ // disable diagnostic mode in mode register
+ mode.diag_mode = 0x0;
+
+ err = i2cRegisterOp( DeviceFW::WRITE,
+ i_target,
+ &mode.value,
+ I2C_REG_MODE,
+ i_args );
+
+
+ if( err )
+ {
+ TRACFCOMP( g_trac_i2c,
+ ERR_MRK"I2C disable Diagnostic mode Failed!!" );
+ // We still need to reset the other ports on this I2C engine
+ errlCommit( err, I2C_COMP_ID );
+ continue;
+ }
+
+
+ } // end of port for loop
}while(0);
@@ -2036,8 +2101,10 @@ errlHndl_t i2cReset ( TARGETING::Target * i_target,
if( err )
{
- //error trying to force a reset break
- break;
+ // We still want to send the slave stop command since the
+ // initial reset completed above.
+ // So just commit the log here and let the function continue.
+ errlCommit( err, I2C_COMP_ID );
}
}
@@ -2114,13 +2181,6 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
// Need to send slave stop to all ports with a device on the engine
for( uint32_t port = 0; port < P8_MASTER_PORTS; port++ )
{
- // Only do port 0 for FSI I2C
- if ( ( i_args.switches.useFsiI2C == 1 ) &&
- ( port != 0 ) )
- {
- break;
- }
-
// Only send stop to a port if there are devices on it
l_speed = speed_array[i_args.engine][port];
if ( l_speed == 0 )
@@ -2139,7 +2199,10 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
i_args );
if( err )
{
- break;
+ // We still need to send the slave stop to the other ports
+ // on this I2C engine
+ errlCommit( err, I2C_COMP_ID );
+ continue;
}
mode.bit_rate_div = i_args.bit_rate_divisor;
@@ -2156,7 +2219,10 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
if( err )
{
- break;
+ // We still need to send the slave stop to the other ports
+ // on this I2C engine
+ errlCommit( err, I2C_COMP_ID );
+ continue;
}
cmd.value = 0x0ull;
@@ -2174,7 +2240,10 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
if( err )
{
- break;
+ // We still need to send the slave stop to the other ports
+ // on this I2C engine
+ errlCommit( err, I2C_COMP_ID );
+ continue;
}
// Now wait for cmd Complete
@@ -2183,7 +2252,10 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
if( err )
{
- break;
+ // We still need to send the slave stop to the other ports
+ // on this I2C engine
+ errlCommit( err, I2C_COMP_ID );
+ continue;
}
} // end of port for-loop
diff --git a/src/usr/i2c/i2c.H b/src/usr/i2c/i2c.H
index c3e5278..4a74663 100755
--- a/src/usr/i2c/i2c.H
+++ b/src/usr/i2c/i2c.H
@@ -723,8 +723,8 @@ errlHndl_t i2cSendStopSignal(TARGETING::Target * i_target,
/**
* @brief This function will reset the I2C Master engine specified
- * by the args. It will also then initiate a Stop cmd to the
- * slave device.
+ * by the args. It will also end the sequence by initiating a Stop
+ * cmd to all ports on the engine that have a slave device.
*
* @param[in] i_target - The I2C master target.
*
--
1.8.2.2