summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMike Baiocchi <baiocchi@us.ibm.com>2015-04-02 13:42:00 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2015-04-09 21:38:09 -0500
commit9419597dac3c8e59da79023acdbda64f1ab0d5ca (patch)
tree3571c55b7ee830642ab265f7a2c30fad985f7043 /src
parent11adfe7dd53ddf8bfb33d82c7de5fc80e08a0666 (diff)
downloadtalos-hostboot-9419597dac3c8e59da79023acdbda64f1ab0d5ca.tar.gz
talos-hostboot-9419597dac3c8e59da79023acdbda64f1ab0d5ca.zip
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 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/16842 Reviewed-by: WILLIAM G. HOFFA <wghoffa@us.ibm.com> Tested-by: Jenkins Server Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/usr/i2c/i2creasoncodes.H1
-rwxr-xr-xsrc/usr/i2c/i2c.C182
-rwxr-xr-xsrc/usr/i2c/i2c.H4
3 files changed, 130 insertions, 57 deletions
diff --git a/src/include/usr/i2c/i2creasoncodes.H b/src/include/usr/i2c/i2creasoncodes.H
index 6dda540da..fda1c142c 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 f8583b8a1..cbb583412 100755
--- a/src/usr/i2c/i2c.C
+++ b/src/usr/i2c/i2c.C
@@ -1927,6 +1927,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()" );
@@ -1934,62 +1939,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);
@@ -2038,8 +2103,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 );
}
}
@@ -2116,13 +2183,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 )
@@ -2141,7 +2201,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;
@@ -2158,7 +2221,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;
@@ -2176,7 +2242,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
@@ -2185,7 +2254,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 c3e52785a..4a7466370 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.
*
OpenPOWER on IntegriCloud