diff options
author | Nick Bofferding <bofferdn@us.ibm.com> | 2018-07-13 15:11:28 -0500 |
---|---|---|
committer | William G. Hoffa <wghoffa@us.ibm.com> | 2018-07-17 17:32:02 -0400 |
commit | ea3d3a6c4f987575e6b5354072003e9b3d8522fc (patch) | |
tree | 57173aceb9c9dcdf987ee7b56522c4fcfc1c088f /src/usr/i2c/i2c.C | |
parent | 85367d8e40ddd620dbe80a38e792ef04d49933aa (diff) | |
download | talos-hostboot-ea3d3a6c4f987575e6b5354072003e9b3d8522fc.tar.gz talos-hostboot-ea3d3a6c4f987575e6b5354072003e9b3d8522fc.zip |
I2C: Inhibit sending slave stop command when SDA and SCL are not both asserted
In I2C reset sequence, code previously only waited until SCL line asserted
and, on timeout, sent a slave stop command anyway. This caused situations where
the I2C master could get locked up for long periods when misbehaving I2C
devices were holding down the clock line. This change waits for both SCL and
SDA to go high before invoking the slave stop command, and if that wait times
out, skips sending the slave stop.
Change-Id: I9cbb783dbaecb3df2cf1171f969e79749f3cd157
CQ: SW437713
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/62436
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: William G. Hoffa <wghoffa@us.ibm.com>
Diffstat (limited to 'src/usr/i2c/i2c.C')
-rwxr-xr-x | src/usr/i2c/i2c.C | 34 |
1 files changed, 25 insertions, 9 deletions
diff --git a/src/usr/i2c/i2c.C b/src/usr/i2c/i2c.C index eb8bb2a17..3b1510fed 100755 --- a/src/usr/i2c/i2c.C +++ b/src/usr/i2c/i2c.C @@ -2864,7 +2864,8 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target, continue; } - // Look for Clock Line (SCL) High such that 'stop' cmd will work + // Look for clock line (SCL) and data line (SDA) to be high + // such that the 'stop' command will work status_reg.value = 0x0ull; size_t delay_ns = 0; for ( ; @@ -2884,7 +2885,8 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target, break; } - if ( status_reg.scl_input_level != 0 ) + if ( (status_reg.scl_input_level != 0) + && (status_reg.sda_input_level != 0) ) { break; } @@ -2904,13 +2906,27 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target, if ( delay_ns > I2C_RESET_POLL_DELAY_TOTAL_NS ) { - // Even though we don't see the Clock Line High, just - // trace a warning here and continue to send the 'stop' cmd - TRACFCOMP( g_trac_i2c, INFO_MRK"i2cSendSlaveStop(): " - "Not seeing SCL High 0x%.16llX after %d ns of " - "polling (max=%d)", - status_reg.value, delay_ns, - I2C_RESET_POLL_DELAY_TOTAL_NS ); + // We don't see both clock and data lines high; in this case + // it's not likely for a slave stop command to work. One + // possible nasty side-effect of attempting slave stop is the + // I2C master can become indefinitely busy and prevent writes + // to the mode register from completing. Just continue to the + // next port. + TRACFCOMP( g_trac_i2c, ERR_MRK"i2cSendSlaveStop(): " + "Not seeing both SCL (%d) and SDA (%d) high " + "after %d ns of polling (max=%d). " + "Full status register = 0x%.16llX. " + "Inhibiting sending slave stop to e%/p% for " + "HUID 0x%08X.", + status_reg.scl_input_level, + status_reg.sda_input_level, + delay_ns, + I2C_RESET_POLL_DELAY_TOTAL_NS, + status_reg.value, + i_args.engine, + port, + TARGETING::get_huid(i_target)); + continue; } cmd.value = 0x0ull; |