diff options
author | Mike Baiocchi <baiocchi@us.ibm.com> | 2015-04-02 13:42:00 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2015-04-09 21:38:09 -0500 |
commit | 9419597dac3c8e59da79023acdbda64f1ab0d5ca (patch) | |
tree | 3571c55b7ee830642ab265f7a2c30fad985f7043 /src | |
parent | 11adfe7dd53ddf8bfb33d82c7de5fc80e08a0666 (diff) | |
download | talos-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.H | 1 | ||||
-rwxr-xr-x | src/usr/i2c/i2c.C | 182 | ||||
-rwxr-xr-x | 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 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. * |