mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-09-22 09:34:56 +02:00
i2c: imx: fix locked bus on SMBus block-read of 0 (atomic)
[ Upstream commitcb2fc37857] SMBus 3.1 6.5.7 allows a Block Read byte count of 0, but the atomic (polling) path rejects it as -EPROTO. Worse, it returns without a NACK+STOP: the next receive cycle has already started, so the target keeps holding SDA and the bus stays stuck until a power cycle for this i2c controller. Reading I2DR to obtain the count likewise arms the next byte on the count > I2C_SMBUS_BLOCK_MAX path, which also returned -EPROTO directly and left the bus held. Handle both: NACK the in-flight dummy byte (TXAK) and extend msgs->len so the existing last-byte handling emits STOP; the dummy byte is discarded. A count of 0 is a valid empty block read; a count above I2C_SMBUS_BLOCK_MAX is still reported as -EPROTO, but only after the bus has been released. The interrupt-driven path has the same flaw from a later commit and is fixed separately, as it carries a different Fixes: tag and stable range. Fixes:8e8782c715("i2c: imx: add SMBus block read support") Signed-off-by: Vincent Jardin <vjardin@free.fr> Cc: <stable@vger.kernel.org> # v3.16+ Acked-by: Oleksij Rempel <o.rempel@pengutronix.de> Acked-by: Carlos Song <carlos.song@nxp.com> Reviewed-by: Stefan Eichenberger <eichest@gmail.com> Signed-off-by: Andi Shyti <andi.shyti@kernel.org> Link: https://lore.kernel.org/r/20260713-for-upstream-i2c-lx2160-fix-v1-v3-1-073ac9e103a5@free.fr Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
9d9c1f10f5
commit
016ef0f6ca
@@ -1184,6 +1184,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
|
||||
int i, result;
|
||||
unsigned int temp;
|
||||
int block_data = msgs->flags & I2C_M_RECV_LEN;
|
||||
int block_err = 0;
|
||||
|
||||
result = i2c_imx_prepare_read(i2c_imx, msgs, atomic, false);
|
||||
if (result)
|
||||
@@ -1205,8 +1206,20 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
|
||||
*/
|
||||
if ((!i) && block_data) {
|
||||
len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
|
||||
if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX))
|
||||
return -EPROTO;
|
||||
if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
|
||||
/*
|
||||
* SMBus 3.1 6.5.7: support count byte of 0.
|
||||
* I2C_SMBUS_BLOCK_MAX case should not hold the SDA either.
|
||||
*/
|
||||
if (len > I2C_SMBUS_BLOCK_MAX)
|
||||
block_err = -EPROTO;
|
||||
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
|
||||
temp |= I2CR_TXAK;
|
||||
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
|
||||
msgs->buf[0] = 0;
|
||||
msgs->len = 2;
|
||||
continue;
|
||||
}
|
||||
dev_dbg(&i2c_imx->adapter.dev,
|
||||
"<%s> read length: 0x%X\n",
|
||||
__func__, len);
|
||||
@@ -1254,7 +1267,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
|
||||
"<%s> read byte: B%d=0x%X\n",
|
||||
__func__, i, msgs->buf[i]);
|
||||
}
|
||||
return 0;
|
||||
return block_err;
|
||||
}
|
||||
|
||||
static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
|
||||
|
||||
Reference in New Issue
Block a user