summaryrefslogtreecommitdiffstats
path: root/src/usr/i2c/i2c.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/i2c/i2c.C')
-rwxr-xr-xsrc/usr/i2c/i2c.C311
1 files changed, 175 insertions, 136 deletions
diff --git a/src/usr/i2c/i2c.C b/src/usr/i2c/i2c.C
index 8c2656f18..1f5cf336a 100755
--- a/src/usr/i2c/i2c.C
+++ b/src/usr/i2c/i2c.C
@@ -5,7 +5,7 @@
/* */
/* IBM CONFIDENTIAL */
/* */
-/* COPYRIGHT International Business Machines Corp. 2011,2013 */
+/* COPYRIGHT International Business Machines Corp. 2011,2014 */
/* */
/* p1 */
/* */
@@ -65,8 +65,7 @@ TRAC_INIT( & g_trac_i2cr, "I2CR", KILOBYTE );
// ----------------------------------------------
// Defines
// ----------------------------------------------
-#define I2C_COMMAND_ATTEMPTS 2 // 1 Retry on failure
-#define I2C_RETRY_DELAY 10000000 // Sleep for 10 ms before retrying
+#define I2C_RESET_DELAY_NS (5 * NS_PER_MSEC) // Sleep for 5 ms after reset
#define MAX_I2C_ENGINES 3 // Maximum of 3 engines per I2C Master
#define P8_MASTER_ENGINES 2 // Number of Engines used in P8
#define CENTAUR_MASTER_ENGINES 1 // Number of Engines in a Centaur
@@ -98,6 +97,7 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType,
va_list i_args )
{
errlHndl_t err = NULL;
+ errlHndl_t err_reset = NULL;
mutex_t * engineLock = NULL;
bool mutex_needs_unlock = false;
@@ -204,169 +204,180 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType,
if( err )
{
+ // Skip performing the actual I2C Operation
break;
}
- for( int attempt = 0; attempt < I2C_COMMAND_ATTEMPTS; attempt++ )
+ /*******************************************************/
+ /* Perform the I2C Operation */
+ /*******************************************************/
+
+ /***********************************************/
+ /* I2C Read with Offset */
+ /***********************************************/
+ if( i_opType == DeviceFW::READ &&
+ l_offset_length != 0 )
{
- if( err )
- {
- // Catch and commit the log here if we failed on first attempt.
- TRACFCOMP( g_trac_i2c,
- ERR_MRK"Error Encountered, Attempt %d out of %d",
- (attempt + 1), // Add 1 since we started counting at 0
- I2C_COMMAND_ATTEMPTS );
- errlCommit( err,
- I2C_COMP_ID );
+ // First WRITE offset to device without a stop
+ args.read_not_write = false;
+ args.with_stop = false;
+ args.skip_mode_setup = false;
- // Reset the I2C Master
- err = i2cReset( i_target,
- args );
+ err = i2cWrite( i_target,
+ l_offset_buffer,
+ l_offset_length,
+ args );
- if( err )
- {
- break;
- }
+ if( err == NULL )
+ {
+ // Now do the READ with a stop
+ args.read_not_write = true;
+ args.with_stop = true;
- // Sleep before trying again.
- nanosleep( 0, I2C_RETRY_DELAY );
- }
+ // Skip mode setup on this cmd -
+ // already set with previous cmd
+ args.skip_mode_setup = true;
+ err = i2cRead( i_target,
+ io_buffer,
+ io_buflen,
+ args );
+ }
+ }
- if( i_opType == DeviceFW::READ &&
- l_offset_length != 0 )
- {
+ /***********************************************/
+ /* I2C Write with Offset */
+ /***********************************************/
+ else if( i_opType == DeviceFW::WRITE &&
+ l_offset_length != 0 )
+ {
- // First WRITE offset to device without a stop
- args.read_not_write = false;
- args.with_stop = false;
- args.skip_mode_setup = false;
+ // Add the Offset Information to the start of the data and
+ // then send as a single write operation
- err = i2cWrite( i_target,
- l_offset_buffer,
- l_offset_length,
- args );
+ size_t newBufLen = l_offset_length + io_buflen;
+ uint8_t * newBuffer = static_cast<uint8_t*>(malloc(newBufLen));
- if( err == NULL )
- {
- // Now do the READ with a stop
- args.read_not_write = true;
- args.with_stop = true;
-
- // Skip mode setup on this cmd -
- // already set with previous cmd
- args.skip_mode_setup = true;
-
- err = i2cRead( i_target,
- io_buffer,
- io_buflen,
- args );
- }
- }
+ // Add the Offset to the buffer
+ memcpy( newBuffer, l_offset_buffer, l_offset_length);
- else if( i_opType == DeviceFW::WRITE &&
- l_offset_length != 0 )
- {
+ // Now add the data the user wanted to write
+ memcpy( &newBuffer[l_offset_length], io_buffer, io_buflen);
- // Add the Offset Information to the start of the data and
- // then send as a single write operation
+ // Write parms:
+ args.read_not_write = false;
+ args.with_stop = true;
+ args.skip_mode_setup = false;
- size_t newBufLen = l_offset_length + io_buflen;
- uint8_t * newBuffer = static_cast<uint8_t*>(malloc(newBufLen));
+ err = i2cWrite( i_target,
+ newBuffer,
+ newBufLen,
+ args );
- // Add the Offset to the buffer
- memcpy( newBuffer, l_offset_buffer, l_offset_length);
- // Now add the data the user wanted to write
- memcpy( &newBuffer[l_offset_length], io_buffer, io_buflen);
+ free( newBuffer );
- // Write parms:
- args.read_not_write = false;
- args.with_stop = true;
- args.skip_mode_setup = false;
+ }
- err = i2cWrite( i_target,
- newBuffer,
- newBufLen,
- args );
+ /***********************************************/
+ /* I2C Read (no offset) */
+ /***********************************************/
+ else if ( i_opType == DeviceFW::READ &&
+ l_offset_length == 0 )
+ {
+ // Do a direct READ
+ args.read_not_write = true;
+ args.with_stop = true;
+ args.skip_mode_setup = false;
+
+ err = i2cRead( i_target,
+ io_buffer,
+ io_buflen,
+ args);
+ }
- free( newBuffer );
+ /***********************************************/
+ /* I2C Write (no offset) */
+ /***********************************************/
+ else if( i_opType == DeviceFW::WRITE &&
+ l_offset_length == 0 )
+ {
+ // Do a direct WRITE with a stop
+ args.read_not_write = false;
+ args.with_stop = true;
+ args.skip_mode_setup = false;
+
+ err = i2cWrite( i_target,
+ io_buffer,
+ io_buflen,
+ args);
+ }
- }
+ /********************************************************/
+ /* Error - Unsupported I2C Op/Offset Type Combination */
+ /********************************************************/
+ else
+ {
+ TRACFCOMP( g_trac_i2c, ERR_MRK"i2cPerformOp() - "
+ "Unsupported Op/Offset-Type Combination=%d/%d",
+ i_opType, l_offset_length );
+ uint64_t userdata2 = l_offset_length;
+ userdata2 = (userdata2 << 16) | args.port;
+ userdata2 = (userdata2 << 16) | args.engine;
+ userdata2 = (userdata2 << 16) | args.devAddr;
- else if ( i_opType == DeviceFW::READ &&
- l_offset_length == 0 )
- {
- // Do a direct READ
- args.read_not_write = true;
- args.with_stop = true;
- args.skip_mode_setup = false;
+ /*@
+ * @errortype
+ * @reasoncode I2C_INVALID_OP_TYPE
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid I2C_PERFORM_OP
+ * @userdata1 i_opType
+ * @userdata2[0:15] Offset Length
+ * @userdata2[16:31] Master Port
+ * @userdata2[32:47] Master Engine
+ * @userdata2[48:63] Slave Device Address
+ * @devdesc Invalid Operation type.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_PERFORM_OP,
+ I2C_INVALID_OP_TYPE,
+ i_opType,
+ userdata2 );
- err = i2cRead( i_target,
- io_buffer,
- io_buflen,
- args);
- }
+ // No Operation performed, so can break and skip the section
+ // that handles operation errors
+ break;
+ }
+ // Handle Error from I2C Operation
+ if( err )
+ {
+ // Reset the I2C Master
+ err_reset = i2cReset( i_target,
+ args );
- else if( i_opType == DeviceFW::WRITE &&
- l_offset_length == 0 )
- {
- // Do a direct WRITE with a stop
- args.read_not_write = false;
- args.with_stop = true;
- args.skip_mode_setup = false;
-
- err = i2cWrite( i_target,
- io_buffer,
- io_buflen,
- args);
- }
- else
+ if( err_reset )
{
+ // 2 error logs, so commit the reset log here
TRACFCOMP( g_trac_i2c, ERR_MRK"i2cPerformOp() - "
- "Unsupported Op/Offset-Type Combination=%d/%d",
- i_opType, l_offset_length );
- uint64_t userdata2 = l_offset_length;
- userdata2 = (userdata2 << 16) | args.port;
- userdata2 = (userdata2 << 16) | args.engine;
- userdata2 = (userdata2 << 16) | args.devAddr;
+ "Previous error (rc=0x%X, eid=0x%X) before "
+ "i2cReset() failed. Committing reset error "
+ "(rc=0x%X, eid=0x%X) and returning original error",
+ err->reasonCode(), err->eid(),
+ err_reset->reasonCode(), err_reset->eid() );
- /*@
- * @errortype
- * @reasoncode I2C_INVALID_OP_TYPE
- * @severity ERRL_SEV_UNRECOVERABLE
- * @moduleid I2C_PERFORM_OP
- * @userdata1 i_opType
- * @userdata2[0:15] Offset Length
- * @userdata2[16:31] Master Port
- * @userdata2[32:47] Master Engine
- * @userdata2[48:63] Slave Device Address
- * @devdesc Invalid Operation type.
- */
- err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- I2C_PERFORM_OP,
- I2C_INVALID_OP_TYPE,
- i_opType,
- userdata2 );
-
- break;
+ errlCommit( err_reset, I2C_COMP_ID );
}
- // If no errors, break here
- if( err == NULL )
- {
- break;
- }
- }
+ // Sleep to allow devices to recover from reset
+ nanosleep( 0, I2C_RESET_DELAY_NS );
- if( err )
- {
break;
}
+
} while( 0 );
// Check if we need to unlock the mutex
@@ -895,6 +906,7 @@ errlHndl_t i2cCheckForErrors ( TARGETING::Target * i_target,
{
errlHndl_t err = NULL;
bool errorFound = false;
+ bool nackFound = false;
uint64_t intRegVal = 0x0;
TRACDCOMP( g_trac_i2c,
@@ -944,7 +956,8 @@ errlHndl_t i2cCheckForErrors ( TARGETING::Target * i_target,
if( 1 == i_statusVal.nack_received )
{
- errorFound = true;
+ // Rather than using 'errorFound', use specific nackFound
+ nackFound = true;
TRACFCOMP( g_trac_i2c,
ERR_MRK"I2C NACK Received! - status reg: %016llx",
i_statusVal.value );
@@ -983,7 +996,7 @@ errlHndl_t i2cCheckForErrors ( TARGETING::Target * i_target,
if( errorFound )
{
TRACFCOMP( g_trac_i2c,
- ERR_MRK"i2cCheckForErrors() - Error(s) found after command complete!" );
+ ERR_MRK"i2cCheckForErrors() - Error(s) found" );
/*@
* @errortype
@@ -1005,6 +1018,33 @@ errlHndl_t i2cCheckForErrors ( TARGETING::Target * i_target,
break;
}
+
+ else if ( nackFound )
+ {
+ TRACFCOMP( g_trac_i2c,
+ ERR_MRK"i2cCheckForErrors() - NACK found (only error)" );
+
+ /*@
+ * @errortype
+ * @reasoncode I2C_NACK_ONLY_FOUND
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid I2C_CHECK_FOR_ERRORS
+ * @userdata1 Status Register Value
+ * @userdata2 Interrupt Register Value
+ * @devdesc Error was found in I2C status register. Check
+ * userdata1 to determine what the error was.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_CHECK_FOR_ERRORS,
+ I2C_NACK_ONLY_FOUND,
+ i_statusVal.value,
+ intRegVal );
+
+ // @todo RTC:69113 - Add target and I2C traces to the errorlog.
+
+ break;
+ }
+
} while( 0 );
TRACDCOMP( g_trac_i2c,
@@ -1189,7 +1229,7 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
TRACUCOMP(g_trac_i2c,"i2cSendSlaveStop(): "
"mode[0x%lx]: 0x%016llx",
- masterAddrs[engine].mode, mode.value );
+ masterAddrs[i_args.engine].mode, mode.value );
err = deviceWrite( i_target,
&mode.value,
@@ -1207,7 +1247,7 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
TRACUCOMP(g_trac_i2c,"i2cSendSlaveStop(): "
"cmd[0x%lx]: 0x%016llx",
- masterAddrs[engine].command, cmd.value );
+ masterAddrs[i_args.engine].command, cmd.value );
err = deviceWrite( i_target,
&cmd.value,
@@ -1269,7 +1309,7 @@ errlHndl_t i2cGetInterrupts ( TARGETING::Target * i_target,
TRACUCOMP(g_trac_i2c,"i2cGetInterrupts(): "
"interrupt[0x%lx]: 0x%016llx",
- masterAddrs[engine].interrupt, intreg.value );
+ masterAddrs[i_args.engine].interrupt, intreg.value );
// Return the data read
o_intRegValue = intreg.value;
@@ -1598,7 +1638,6 @@ errlHndl_t i2cSetBusVariables ( TARGETING::Target * i_target,
} while( 0 );
-
TRACUCOMP(g_trac_i2c,"i2cSetBusVariables(): e/p/dA=%d/%d/0x%x: "
"mode=%d: b_sp=%d, b_r_d=0x%x, to_i=%d, to_c = %d",
io_args.engine, io_args.port, io_args.devAddr,
OpenPOWER on IntegriCloud