linux-i2c.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1] i2c: designware: Handle invalid SMBus block data response length
@ 2023-05-23  8:21 Tam Nguyen
  2023-05-24 12:33 ` Jarkko Nikula
  0 siblings, 1 reply; 5+ messages in thread
From: Tam Nguyen @ 2023-05-23  8:21 UTC (permalink / raw)
  To: linux-kernel, linux-i2c
  Cc: patches, jarkko.nikula, andriy.shevchenko, mika.westerberg, jsd,
	tamnguyenchi, chuong, darren, stable

In I2C_FUNC_SMBUS_BLOCK_DATA case, the I2C Designware driver does not
handle correctly when it receives the length of SMBus block data
response from SMBus slave device, which is outside the range 1-32 bytes.
Consequently, the I2C Designware bus is stuck and cannot recover.
Because if IC_EMPTYFIFO_HOLD_MASTER_EN is set, which cannot be detected
from the registers, the controller can be disabled if the STOP bit is set.
But it is only set after receiving block data response length.

Hence, to prevent the bus from stuck condition, after receiving the
invalid block data response length, the driver will read another byte
with STOP bit set.

Cc: stable@vger.kernel.org
Signed-off-by: Tam Nguyen <tamnguyenchi@os.amperecomputing.com>
---
 drivers/i2c/busses/i2c-designware-master.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 55ea91a63382..94dadd785ed0 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -527,8 +527,19 @@ i2c_dw_read(struct dw_i2c_dev *dev)
 
 			regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
 			/* Ensure length byte is a valid value */
-			if (flags & I2C_M_RECV_LEN &&
-			    (tmp & DW_IC_DATA_CMD_DAT) <= I2C_SMBUS_BLOCK_MAX && tmp > 0) {
+			if (flags & I2C_M_RECV_LEN) {
+				/*
+				 * if IC_EMPTYFIFO_HOLD_MASTER_EN is set, which cannot be
+				 * detected from the registers, the controller can be
+				 * disabled if the STOP bit is set. But it is only set
+				 * after receiving block data response length in
+				 * I2C_FUNC_SMBUS_BLOCK_DATA case. That needs to read
+				 * another byte with STOP bit set when the block data
+				 * response length is invalid to complete the transaction.
+				 */
+				if ((tmp & DW_IC_DATA_CMD_DAT) > I2C_SMBUS_BLOCK_MAX || tmp == 0)
+					tmp = 1;
+
 				len = i2c_dw_recv_len(dev, tmp);
 			}
 			*buf++ = tmp;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-06-05  7:41 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-23  8:21 [PATCH v1] i2c: designware: Handle invalid SMBus block data response length Tam Nguyen
2023-05-24 12:33 ` Jarkko Nikula
2023-05-25  9:30   ` Tam Chi Nguyen
2023-06-02  4:30     ` Tam Chi Nguyen
2023-06-05  7:41       ` Jarkko Nikula

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).