public inbox for linux-i2c@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH V3 0/2] i2c: imx: Fix block read handling for invalid length
@ 2026-01-16 11:19 LI Qingwu
  2026-01-16 11:19 ` [PATCH V3 1/2] i2c: imx: preserve error state in block data length handler LI Qingwu
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: LI Qingwu @ 2026-01-16 11:19 UTC (permalink / raw)
  To: o.rempel, kernel, andi.shyti, shawnguo, s.hauer, festevam,
	linux-i2c, imx, linux-arm-kernel, linux-kernel
  Cc: bsp-development.geo, LI Qingwu

This series fixes a crash and bus lockup when SMBus block read operations
encounter invalid length values (zero or greater than I2C_SMBUS_BLOCK_MAX).

Both patches have been tested on i.MX 8M Plus with continuous block read
operations from battery and keyboard devices sharing the same I2C bus.

Changes in v3:
  - Add trailing comma to IMX_I2C_STATE_READ_BLOCK_DATA_ABORT enum
  - Clean up reference manual citations

LI Qingwu (2):
  i2c: imx: preserve error state in block data length handler
  i2c: imx: add abort path for invalid block length

 drivers/i2c/busses/i2c-imx.c | 58 ++++++++++++++++++++++++++++++++++--
 1 file changed, 55 insertions(+), 3 deletions(-)

-- 
2.43.0


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

* [PATCH V3 1/2] i2c: imx: preserve error state in block data length handler
  2026-01-16 11:19 [PATCH V3 0/2] i2c: imx: Fix block read handling for invalid length LI Qingwu
@ 2026-01-16 11:19 ` LI Qingwu
  2026-01-22 10:48   ` Andi Shyti
  2026-01-16 11:19 ` [PATCH V3 2/2] i2c: imx: add abort path for invalid block length LI Qingwu
  2026-01-28 22:19 ` [PATCH V3 0/2] i2c: imx: Fix block read handling for invalid length Andi Shyti
  2 siblings, 1 reply; 6+ messages in thread
From: LI Qingwu @ 2026-01-16 11:19 UTC (permalink / raw)
  To: o.rempel, kernel, andi.shyti, shawnguo, s.hauer, festevam,
	linux-i2c, imx, linux-arm-kernel, linux-kernel
  Cc: bsp-development.geo, LI Qingwu

When a block read returns an invalid length, zero or >I2C_SMBUS_BLOCK_MAX,
the length handler sets the state to IMX_I2C_STATE_FAILED. However,
i2c_imx_master_isr() unconditionally overwrites this with
IMX_I2C_STATE_READ_CONTINUE, causing an endless read loop that overruns
buffers and crashes the system.

Guard the state transition to preserve error states set by the length
handler.

Signed-off-by: LI Qingwu <Qing-wu.Li@leica-geosystems.com.cn>
---
 drivers/i2c/busses/i2c-imx.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 205cc132fdec..05ba41144648 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -1102,7 +1102,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


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

* [PATCH V3 2/2] i2c: imx: add abort path for invalid block length
  2026-01-16 11:19 [PATCH V3 0/2] i2c: imx: Fix block read handling for invalid length LI Qingwu
  2026-01-16 11:19 ` [PATCH V3 1/2] i2c: imx: preserve error state in block data length handler LI Qingwu
@ 2026-01-16 11:19 ` LI Qingwu
  2026-01-28 22:19 ` [PATCH V3 0/2] i2c: imx: Fix block read handling for invalid length Andi Shyti
  2 siblings, 0 replies; 6+ messages in thread
From: LI Qingwu @ 2026-01-16 11:19 UTC (permalink / raw)
  To: o.rempel, kernel, andi.shyti, shawnguo, s.hauer, festevam,
	linux-i2c, imx, linux-arm-kernel, linux-kernel
  Cc: bsp-development.geo, LI Qingwu

When a block read returns an invalid length (0 or >I2C_SMBUS_BLOCK_MAX),
the current implementation leaves the bus hanging with SDA held low,
blocking all further I2C communication on the bus.

Add a dedicated IMX_I2C_STATE_READ_BLOCK_DATA_ABORT state and ISR
handler to properly terminate the transfer when an invalid block length
is detected:
  - Set TXAK and receive the next byte with NACK
  - On the following interrupt, generate a Stop condition
  - Read and discard the final byte
  - Report -EPROTO to the caller

This ensures the bus is released correctly and allows other devices on
the bus to continue operating normally.

Tested on i.MX 8M Plus with continuous block read operations.

Signed-off-by: LI Qingwu <Qing-wu.Li@leica-geosystems.com.cn>
---
 drivers/i2c/busses/i2c-imx.c | 55 ++++++++++++++++++++++++++++++++++--
 1 file changed, 53 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 05ba41144648..d3fbc2df7f04 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -232,6 +232,7 @@ enum imx_i2c_state {
 	IMX_I2C_STATE_READ_CONTINUE,
 	IMX_I2C_STATE_READ_BLOCK_DATA,
 	IMX_I2C_STATE_READ_BLOCK_DATA_LEN,
+	IMX_I2C_STATE_READ_BLOCK_DATA_ABORT,
 };
 
 struct imx_i2c_struct {
@@ -1053,14 +1054,60 @@ static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx)
 	i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
 }
 
+static inline void i2c_imx_isr_read_block_data_abort(struct imx_i2c_struct *i2c_imx)
+{
+	unsigned int temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+
+	if (i2c_imx->is_lastmsg) {
+		/*
+		 * Last byte to read.
+		 *
+		 * Ref: IMX8MPRM Rev. 1, 06/2021: 17.1.4.4 Generation of Stop
+		 *
+		 * Ref: IMX8MPRM Rev. 1, 06/2021: Figure 17-5.
+		 * Flowchart of typical I2C interrupt routine
+		 *
+		 * Before the last byte is read, a Stop signal must be generated.
+		 */
+		temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+		if (!(temp & I2CR_MSTA))
+			i2c_imx->stopped = 1;
+		temp &= ~(I2CR_MSTA | I2CR_MTX);
+		imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+		imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+		i2c_imx->state = IMX_I2C_STATE_FAILED;
+		wake_up(&i2c_imx->queue);
+	} else {
+		/*
+		 * Next-to-last byte to read.
+		 *
+		 * Ref: IMX8MPRM Rev. 1, 06/2021: 17.1.4.4 Generation of Stop
+		 *
+		 * Ref: IMX8MPRM Rev. 1, 06/2021: Figure 17-5.
+		 * Flowchart of typical I2C interrupt routine
+		 *
+		 * For a master receiver to terminate a data transfer, it must
+		 * inform the slave transmitter by not acknowledging the last
+		 * data byte. This is done by setting the transmit acknowledge
+		 * bit (I2C_I2CR[TXAK]) before reading the next-to-last byte.
+		 */
+		temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+		temp |= I2CR_TXAK;
+		imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+		imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+		i2c_imx->is_lastmsg = true;
+	}
+}
+
 static inline void i2c_imx_isr_read_block_data_len(struct imx_i2c_struct *i2c_imx)
 {
 	u8 len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
 
 	if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) {
 		i2c_imx->isr_result = -EPROTO;
-		i2c_imx->state = IMX_I2C_STATE_FAILED;
-		wake_up(&i2c_imx->queue);
+		i2c_imx->state = IMX_I2C_STATE_READ_BLOCK_DATA_ABORT;
+		i2c_imx->is_lastmsg = false;
+		return;
 	}
 	i2c_imx->msg->len += len;
 	i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = len;
@@ -1106,6 +1153,10 @@ static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned i
 			i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE;
 		break;
 
+	case IMX_I2C_STATE_READ_BLOCK_DATA_ABORT:
+		i2c_imx_isr_read_block_data_abort(i2c_imx);
+		break;
+
 	case IMX_I2C_STATE_WRITE:
 		if (i2c_imx_isr_write(i2c_imx))
 			break;
-- 
2.43.0


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

* Re: [PATCH V3 1/2] i2c: imx: preserve error state in block data length handler
  2026-01-16 11:19 ` [PATCH V3 1/2] i2c: imx: preserve error state in block data length handler LI Qingwu
@ 2026-01-22 10:48   ` Andi Shyti
  2026-01-22 12:18     ` Stefan Eichenberger
  0 siblings, 1 reply; 6+ messages in thread
From: Andi Shyti @ 2026-01-22 10:48 UTC (permalink / raw)
  To: LI Qingwu
  Cc: o.rempel, kernel, shawnguo, Stefan Eichenberger, s.hauer,
	festevam, linux-i2c, imx, linux-arm-kernel, linux-kernel,
	bsp-development.geo

Hi Li,

I'm adding also Stefan in the Cc list as he has authored the
lines you are changing.

On Fri, Jan 16, 2026 at 11:19:05AM +0000, LI Qingwu wrote:
> When a block read returns an invalid length, zero or >I2C_SMBUS_BLOCK_MAX,
> the length handler sets the state to IMX_I2C_STATE_FAILED. However,
> i2c_imx_master_isr() unconditionally overwrites this with
> IMX_I2C_STATE_READ_CONTINUE, causing an endless read loop that overruns
> buffers and crashes the system.
> 
> Guard the state transition to preserve error states set by the length
> handler.
> 
> Signed-off-by: LI Qingwu <Qing-wu.Li@leica-geosystems.com.cn>

I asked you to add the Fixes tag here. Perhaps you need to add:

Fixes: 5f5c2d4579ca ("i2c: imx: prevent rescheduling in non dma mode")
Cc Stefan Eichenberger <stefan.eichenberger@toradex.com>
Cc: <stable@vger.kernel.org> # v6.13+

You can get the information above with "git blame".

I'll wait for comments from Oleksij and/or Stefan here.

Andi

> ---
>  drivers/i2c/busses/i2c-imx.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
> index 205cc132fdec..05ba41144648 100644
> --- a/drivers/i2c/busses/i2c-imx.c
> +++ b/drivers/i2c/busses/i2c-imx.c
> @@ -1102,7 +1102,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
> 

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

* Re: [PATCH V3 1/2] i2c: imx: preserve error state in block data length handler
  2026-01-22 10:48   ` Andi Shyti
@ 2026-01-22 12:18     ` Stefan Eichenberger
  0 siblings, 0 replies; 6+ messages in thread
From: Stefan Eichenberger @ 2026-01-22 12:18 UTC (permalink / raw)
  To: Andi Shyti
  Cc: LI Qingwu, o.rempel, kernel, shawnguo, Stefan Eichenberger,
	s.hauer, festevam, linux-i2c, imx, linux-arm-kernel, linux-kernel,
	bsp-development.geo

Hi Andi and Li,

On Thu, Jan 22, 2026 at 11:48:54AM +0100, Andi Shyti wrote:
> Hi Li,
> 
> I'm adding also Stefan in the Cc list as he has authored the
> lines you are changing.
> 
> On Fri, Jan 16, 2026 at 11:19:05AM +0000, LI Qingwu wrote:
> > When a block read returns an invalid length, zero or >I2C_SMBUS_BLOCK_MAX,
> > the length handler sets the state to IMX_I2C_STATE_FAILED. However,
> > i2c_imx_master_isr() unconditionally overwrites this with
> > IMX_I2C_STATE_READ_CONTINUE, causing an endless read loop that overruns
> > buffers and crashes the system.
> > 
> > Guard the state transition to preserve error states set by the length
> > handler.
> > 
> > Signed-off-by: LI Qingwu <Qing-wu.Li@leica-geosystems.com.cn>
> 
> I asked you to add the Fixes tag here. Perhaps you need to add:
> 
> Fixes: 5f5c2d4579ca ("i2c: imx: prevent rescheduling in non dma mode")
> Cc Stefan Eichenberger <stefan.eichenberger@toradex.com>
> Cc: <stable@vger.kernel.org> # v6.13+
> 
> You can get the information above with "git blame".
> 
> I'll wait for comments from Oleksij and/or Stefan here.
> 
> Andi
> 
> > ---
> >  drivers/i2c/busses/i2c-imx.c | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
> > index 205cc132fdec..05ba41144648 100644
> > --- a/drivers/i2c/busses/i2c-imx.c
> > +++ b/drivers/i2c/busses/i2c-imx.c
> > @@ -1102,7 +1102,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
> > 

It looks good to me, thanks for the fix. I wonder if the functions in
the isr should instead better return a status and based on that we
decide if we have to change the state or not. Then we would have the
decision to what state we swtich at one place. However, this would
probably be too much rework for that fix.

Therefore, if you add the fixes tag suggested by Andi:
Reviewed-by: Stefan Eichenberger <eichest@gmail.com>

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

* Re: [PATCH V3 0/2] i2c: imx: Fix block read handling for invalid length
  2026-01-16 11:19 [PATCH V3 0/2] i2c: imx: Fix block read handling for invalid length LI Qingwu
  2026-01-16 11:19 ` [PATCH V3 1/2] i2c: imx: preserve error state in block data length handler LI Qingwu
  2026-01-16 11:19 ` [PATCH V3 2/2] i2c: imx: add abort path for invalid block length LI Qingwu
@ 2026-01-28 22:19 ` Andi Shyti
  2 siblings, 0 replies; 6+ messages in thread
From: Andi Shyti @ 2026-01-28 22:19 UTC (permalink / raw)
  To: LI Qingwu
  Cc: o.rempel, kernel, shawnguo, s.hauer, festevam, linux-i2c, imx,
	linux-arm-kernel, linux-kernel, bsp-development.geo

Hi Li,

> LI Qingwu (2):
>   i2c: imx: preserve error state in block data length handler

I merged this patch in i2c/i2c-host-fixes.

>   i2c: imx: add abort path for invalid block length

For this patch I want the review from Oleksij. Oleksij? :-)

Thanks,
Andi

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

end of thread, other threads:[~2026-01-28 22:19 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-16 11:19 [PATCH V3 0/2] i2c: imx: Fix block read handling for invalid length LI Qingwu
2026-01-16 11:19 ` [PATCH V3 1/2] i2c: imx: preserve error state in block data length handler LI Qingwu
2026-01-22 10:48   ` Andi Shyti
2026-01-22 12:18     ` Stefan Eichenberger
2026-01-16 11:19 ` [PATCH V3 2/2] i2c: imx: add abort path for invalid block length LI Qingwu
2026-01-28 22:19 ` [PATCH V3 0/2] i2c: imx: Fix block read handling for invalid length Andi Shyti

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox