[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID:
<VI2PR04MB11147E578957B70705DC14AEAE882A@VI2PR04MB11147.eurprd04.prod.outlook.com>
Date: Fri, 9 Jan 2026 03:02:04 +0000
From: Carlos Song <carlos.song@....com>
To: LI Qingwu <Qing-wu.Li@...ca-geosystems.com.cn>, "o.rempel@...gutronix.de"
<o.rempel@...gutronix.de>, "kernel@...gutronix.de" <kernel@...gutronix.de>,
"andi.shyti@...nel.org" <andi.shyti@...nel.org>, "shawnguo@...nel.org"
<shawnguo@...nel.org>, "s.hauer@...gutronix.de" <s.hauer@...gutronix.de>,
"festevam@...il.com" <festevam@...il.com>, "linux-i2c@...r.kernel.org"
<linux-i2c@...r.kernel.org>, "imx@...ts.linux.dev" <imx@...ts.linux.dev>,
"linux-arm-kernel@...ts.infradead.org"
<linux-arm-kernel@...ts.infradead.org>, "linux-kernel@...r.kernel.org"
<linux-kernel@...r.kernel.org>
CC: "bsp-development.geo@...ca-geosystems.com"
<bsp-development.geo@...ca-geosystems.com>
Subject: [PATCH V1] i2c: imx: Fix SMBus block read hang on zero length
> -----Original Message-----
> From: LI Qingwu <Qing-wu.Li@...ca-geosystems.com.cn>
> Sent: Monday, December 29, 2025 4:16 PM
> To: o.rempel@...gutronix.de; kernel@...gutronix.de; andi.shyti@...nel.org;
> shawnguo@...nel.org; s.hauer@...gutronix.de; festevam@...il.com;
> linux-i2c@...r.kernel.org; imx@...ts.linux.dev;
> linux-arm-kernel@...ts.infradead.org; linux-kernel@...r.kernel.org
> Cc: bsp-development.geo@...ca-geosystems.com; LI Qingwu
> <Qing-wu.Li@...ca-geosystems.com.cn>
> Subject: [EXT] [PATCH V1] i2c: imx: Fix SMBus block read hang on zero length
>
> Caution: This is an external email. Please take care when clicking links or
> opening attachments. When in doubt, report the message using the 'Report
> this email' button
>
>
> SMBus block read transfers encode the payload length in the first data byte.
> When this first byte is zero, there is no payload and the transaction should
> terminate immediately.
>
> On i.MX, if the first byte of an SMBus block read is zero, the driver
> unconditionally overwrites the state with IMX_I2C_STATE_READ_CONTINUE.
> This causes the state machine to enter an endless read loop, eventually
> overrunning internal buffers and leading to a crash.
>
> At the same time, the controller remains in master receive mode and never
> generates a proper STOP condition, leaving the I2C bus permanently busy and
> preventing any further transfers on the bus.
>
> Fix this by handling the zero-length case explicitly: when the first byte is zero,
> ensure that a clean STOP is generated. In this situation the controller is in
> master receive mode, so it must be switched to master transmit mode before
> stopping. This is done by draining the pending received byte from I2DR, setting
> I2CR_MTX to enter transmit mode, waiting briefly for the mode change, and
> then proceeding with the normal STOP sequence.
>
> This change has been tested on i.MX 8M Plus platform.
>
> Signed-off-by: LI Qingwu <Qing-wu.Li@...ca-geosystems.com.cn>
> ---
> drivers/i2c/busses/i2c-imx.c | 13 ++++++++++++-
> 1 file changed, 12 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index
> dcce882f3eba..f40deecf0f66 100644
> --- a/drivers/i2c/busses/i2c-imx.c
> +++ b/drivers/i2c/busses/i2c-imx.c
> @@ -735,6 +735,16 @@ static void i2c_imx_stop(struct imx_i2c_struct
> *i2c_imx, bool atomic)
> temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> if (!(temp & I2CR_MSTA))
> i2c_imx->stopped = 1;
> + if ((temp & I2CR_MSTA) && !(temp & I2CR_MTX)) {
> + (void)imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
> + temp |= I2CR_MTX;
> + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> + if (atomic)
> + udelay(25);
> + else
> + usleep_range(25, 50);
> + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> + }
Hi,
for fix a smbus block read stop, you added these codes to normal stop logic. Could you help check if it will effect stop in other path like i2c DMA/CPU read/write stop logic except for smbus block read?
And do you have mind to move this logic to smbus block read error path? This may be a minimal fix?
Carlos
> temp &= ~(I2CR_MSTA | I2CR_MTX);
> if (i2c_imx->dma)
> temp &= ~I2CR_DMAEN; @@ -1103,7 +1113,8
> @@ static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx,
> unsigned i
>
> case IMX_I2C_STATE_READ_BLOCK_DATA_LEN:
> i2c_imx_isr_read_block_data_len(i2c_imx);
> - i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE;
> + if (i2c_imx->state ==
> IMX_I2C_STATE_READ_BLOCK_DATA_LEN)
> + i2c_imx->state =
> IMX_I2C_STATE_READ_CONTINUE;
> break;
>
> case IMX_I2C_STATE_WRITE:
> --
> 2.43.0
>
Powered by blists - more mailing lists