FAILED: patch "[PATCH] i2c: imx: fix locked bus on SMBus block-read of 0 (atomic)" failed to apply to 6.12-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x cb2fc37857693b55909fb77dc2c87cfbc1cdc476
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026072035-flight-slacker-b884@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From cb2fc37857693b55909fb77dc2c87cfbc1cdc476 Mon Sep 17 00:00:00 2001
From: Vincent Jardin <[email protected]>
Date: Mon, 13 Jul 2026 20:11:59 +0200
Subject: [PATCH] i2c: imx: fix locked bus on SMBus block-read of 0 (atomic)
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.
drivers/i2c/busses/i2c-imx.c +16 -3
@@ -1415,6 +1415,7 @@ static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx,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, false);if (result)
@@ -1436,8 +1437,20 @@ static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx,*/ 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);
@@ -1485,7 +1498,7 @@ static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx,"<%s> read byte: B%d=0x%X\n" , __func__, i, msgs->buf[i]); } -return 0 ; +return block_err; } static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
Sasha Levin
maintainerPATCH 1/2 i2c: imx: separate atomic, dma and non-dma use case
From: Stefan Eichenberger <[email protected]>
[ Upstream commit b460b15b3cc23ef3639cc51043bf8b2a70ca1878 ]
Separate the atomic, dma and non-dma use case as a preparation step for moving the non-dma use case to the isr to avoid rescheduling while a transfer is in progress.
Stable-dep-of: cb2fc3785769 ("i2c: imx: fix locked bus on SMBus block-read of 0 (atomic)")
--- drivers/i2c/busses/i2c-imx.c | 107 +++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 37 deletions(-)
drivers/i2c/busses/i2c-imx.c +70 -37
@@ -1007,6 +1007,43 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,return i2c_imx_acked (i2c_imx); } +static int i2c_imx_prepare_read (struct imx_i2c_struct *i2c_imx, +struct i2c_msg *msgs,bool atomic, +bool use_dma) +{ +int result; +unsigned int temp =0 ; + +/* write slave address */ +imx_i2c_write_reg (i2c_8bit_addr_from_msg (msgs), i2c_imx,IMX_I2C_I2DR ); + result =i2c_imx_trx_complete (i2c_imx, atomic); +if (result) +return result; + result =i2c_imx_acked (i2c_imx); +if (result) +return result; + +dev_dbg (&i2c_imx->adapter.dev,"<%s> setup bus\n" , __func__); + +/* setup bus to read data */ + temp =imx_i2c_read_reg (i2c_imx,IMX_I2C_I2CR ); + temp &= ~I2CR_MTX ; + +/* +* Reset the I2CR_TXAK flag initially for SMBus block read since the +* length is unknown +*/ +if (msgs->len -1 ) + temp &= ~I2CR_TXAK ; +if (use_dma) + temp |=I2CR_DMAEN ; + +imx_i2c_write_reg (temp, i2c_imx,IMX_I2C_I2CR ); +imx_i2c_read_reg (i2c_imx,IMX_I2C_I2DR );/* dummy read */ + +return 0 ; +} +static int i2c_imx_dma_read (struct imx_i2c_struct *i2c_imx,struct i2c_msg *msgs,bool is_lastmsg) {
@@ -1017,6 +1054,11 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,struct imx_i2c_dma *dma = i2c_imx->dma;struct device *dev = &i2c_imx->adapter.dev; + result =i2c_imx_prepare_read (i2c_imx, msgs, false, true); +if (result) +return result; + +dev_dbg (&i2c_imx->adapter.dev,"<%s> read data\n" , __func__); dma->chan_using = dma->chan_rx; dma->dma_transfer_dir =DMA_DEV_TO_MEM ;
@@ -1127,50 +1169,24 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,return 0 ; } +static int i2c_imx_atomic_write (struct imx_i2c_struct *i2c_imx,struct i2c_msg *msgs) +{ +return i2c_imx_write (i2c_imx, msgs, true); +} +static int i2c_imx_read (struct imx_i2c_struct *i2c_imx,struct i2c_msg *msgs,bool is_lastmsg,bool atomic) {int i, result;unsigned int temp;int block_data = msgs->flags &I2C_M_RECV_LEN ; -int use_dma = i2c_imx->dma && msgs->flags &I2C_M_DMA_SAFE && - msgs->len >=DMA_THRESHOLD && !block_data; -dev_dbg (&i2c_imx->adapter.dev, -"<%s> write slave address: addr=0x%x\n" , - __func__,i2c_8bit_addr_from_msg (msgs)); - -/* write slave address */ -imx_i2c_write_reg (i2c_8bit_addr_from_msg (msgs), i2c_imx,IMX_I2C_I2DR ); - result =i2c_imx_trx_complete (i2c_imx, atomic); + result =i2c_imx_prepare_read (i2c_imx, msgs, atomic, false);if (result)return result; - result =i2c_imx_acked (i2c_imx); -if (result) -return result; - -dev_dbg (&i2c_imx->adapter.dev,"<%s> setup bus\n" , __func__); - -/* setup bus to read data */ - temp =imx_i2c_read_reg (i2c_imx,IMX_I2C_I2CR ); - temp &= ~I2CR_MTX ; - -/* -* Reset the I2CR_TXAK flag initially for SMBus block read since the -* length is unknown -*/ -if ((msgs->len -1 ) || block_data) - temp &= ~I2CR_TXAK ; -if (use_dma) - temp |=I2CR_DMAEN ; -imx_i2c_write_reg (temp, i2c_imx,IMX_I2C_I2CR ); -imx_i2c_read_reg (i2c_imx,IMX_I2C_I2DR );/* dummy read */ dev_dbg (&i2c_imx->adapter.dev,"<%s> read data\n" , __func__); -if (use_dma) -return i2c_imx_dma_read (i2c_imx, msgs, is_lastmsg); -/* read data */ for (i =0 ; i < msgs->len; i++) {u8 len =0 ;
@@ -1237,6 +1253,12 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,return 0 ; } +static int i2c_imx_atomic_read (struct imx_i2c_struct *i2c_imx,struct i2c_msg *msgs, +bool is_lastmsg) +{ +return i2c_imx_read (i2c_imx, msgs, is_lastmsg, true); +} +static int i2c_imx_xfer_common (struct i2c_adapter *adapter,struct i2c_msg *msgs,int num,bool atomic) {
@@ -1244,6 +1266,7 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter,int result;bool is_lastmsg = false;struct imx_i2c_struct *i2c_imx =i2c_get_adapdata (adapter); +int use_dma =0 ;/* Start I2C transfer */ result =i2c_imx_start (i2c_imx, atomic);
@@ -1296,15 +1319,25 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter, (temp &I2SR_SRW ?1 :0 ), (temp &I2SR_IIF ?1 :0 ), (temp & I2SR_RXAK ? 1 : 0));#endif + + use_dma = i2c_imx->dma && msgs[i].len >=DMA_THRESHOLD && + msgs[i].flags &I2C_M_DMA_SAFE ;if (msgs[i].flags &I2C_M_RD ) { - result =i2c_imx_read (i2c_imx, &msgs[i], is_lastmsg, atomic); +int block_data = msgs->flags &I2C_M_RECV_LEN ; + +if (atomic) + result =i2c_imx_atomic_read (i2c_imx, &msgs[i], is_lastmsg); +else if (use_dma && !block_data) + result =i2c_imx_dma_read (i2c_imx, &msgs[i], is_lastmsg); +else + result =i2c_imx_read (i2c_imx, &msgs[i], is_lastmsg, false); }else { -if (!atomic && - i2c_imx->dma && msgs[i].len >=DMA_THRESHOLD && - msgs[i].flags &I2C_M_DMA_SAFE ) +if (atomic) + result =i2c_imx_atomic_write (i2c_imx, &msgs[i]); +else if (use_dma) result =i2c_imx_dma_write (i2c_imx, &msgs[i]);else - result =i2c_imx_write (i2c_imx, &msgs[i], atomic); + result =i2c_imx_write (i2c_imx, &msgs[i], false); }if (result) goto fail0;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 i2c: imx: fix locked bus on SMBus block-read of 0 (atomic)
From: Vincent Jardin <[email protected]>
[ Upstream commit cb2fc37857693b55909fb77dc2c87cfbc1cdc476 ]
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.
--- drivers/i2c/busses/i2c-imx.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
drivers/i2c/busses/i2c-imx.c +16 -3
@@ -1180,6 +1180,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)
@@ -1201,8 +1202,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);
@@ -1250,7 +1263,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,
Signature · 1 line
2.53.0