i2c: omap: ensure writes to dev->buf_len are ordered
Subsystems (4)
PATCH 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
if we allow compiler reorder our writes, we could fall into a situation where dev->buf_len is reset for no apparent reason.
This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size, dev->buf_len was reset to zero before we had an oportunity to handle XDR Interrupt. Because dev->buf_len was zero, we entered omap_i2c_transmit_data() to transfer zero bytes, which would mean we would just silently exit omap_i2c_transmit_data() without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes.
After adding the memory barrier, we also drop resetting dev->buf_len to zero in omap_i2c_xfer_msg() because both omap_i2c_transmit_data() and omap_i2c_receive_data() will act until dev->buf_len reaches zero, rendering the other write in omap_i2c_xfer_msg() redundant.
This patch has been tested with pandaboard for a few iterations of the script mentioned above.
---
This bug has been there forever, but it's quite annoying. I think it deserves being pushed upstream during this -rc cycle, but if Wolfram decides to wait until v3.8, I don't mind.
drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/i2c/busses/i2c-omap.c +1 -1
@@ -521,6 +521,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,/* REVISIT: Could the STB bit of I2C_CON be used with probing? */ dev->buf = msg->buf; dev->buf_len = msg->len; +wmb ();omap_i2c_write_reg (dev,OMAP_I2C_CNT_REG , dev->buf_len);
@@ -579,7 +580,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,*/ timeout =wait_for_completion_timeout (&dev->cmd_complete,OMAP_I2C_TIMEOUT ); - dev->buf_len =0 ;if (timeout ==0 ) {dev_err (dev->dev,"controller timed out\n" );omap_i2c_init (dev);
Signature · 1 line
1.8.0
PATCH 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
Quoted 17 lines · Felipe Balbi
if we allow compiler reorder our writes, we could fall into a situation where
dev->buf_lenis reset for no apparent reason.This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size,
dev->buf_lenwas reset to zero before we had an oportunity to handle XDR Interrupt. Becausedev->buf_lenwas zero, we enteredomap_i2c_transmit_data()to transfer zero bytes, which would mean we would just silently exitomap_i2c_transmit_data()without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes.
Quoted 8 lines
After adding the memory barrier, we also drop resetting
dev->buf_lento zero inomap_i2c_xfer_msg()because bothomap_i2c_transmit_data()andomap_i2c_receive_data()will act untildev->buf_lenreaches zero, rendering the other write inomap_i2c_xfer_msg()redundant.This patch has been tested with pandaboard for a few iterations of the script mentioned above.
looks good to me
Quoted 39 lines
Signed-off-by Felipe Balbi <[email protected]>---
This bug has been there forever, but it's quite annoying. I think it deserves being pushed upstream during this -rc cycle, but if Wolfram decides to wait until v3.8, I don't mind.
drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/i2c/busses/i2c-omap.c +1
-2@@ -521,6 +521,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,/* REVISIT: Could the STB bit of I2C_CON be used with probing? */ dev->buf = msg->buf; dev->buf_len = msg->len; +wmb ();omap_i2c_write_reg (dev,OMAP_I2C_CNT_REG , dev->buf_len);@@ -579,7 +580,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,*/ timeout =wait_for_completion_timeout (&dev->cmd_complete,OMAP_I2C_TIMEOUT ); - dev->buf_len =0 ;if (timeout ==0 ) {dev_err (dev->dev,"controller timed out\n" );omap_i2c_init (dev); --1.8.0
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
In reply to Felipe Balbi+Paul
Quoted 3 lines · Felipe Balbi
if we allow compiler reorder our writes, we could fall into a situation where
dev->buf_lenis reset for no apparent reason.
Any chance this would help with the bug Paul found with I2C timeouts on beagle userspace startup?
Kevin
Quoted 53 lines
This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size,
dev->buf_lenwas reset to zero before we had an oportunity to handle XDR Interrupt. Becausedev->buf_lenwas zero, we enteredomap_i2c_transmit_data()to transfer zero bytes, which would mean we would just silently exitomap_i2c_transmit_data()without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes.After adding the memory barrier, we also drop resetting
dev->buf_lento zero inomap_i2c_xfer_msg()because bothomap_i2c_transmit_data()andomap_i2c_receive_data()will act untildev->buf_lenreaches zero, rendering the other write inomap_i2c_xfer_msg()redundant.This patch has been tested with pandaboard for a few iterations of the script mentioned above.
Signed-off-by Felipe Balbi <[email protected]>---
This bug has been there forever, but it's quite annoying. I think it deserves being pushed upstream during this -rc cycle, but if Wolfram decides to wait until v3.8, I don't mind.
drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/i2c/busses/i2c-omap.c +1
-1@@ -521,6 +521,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,/* REVISIT: Could the STB bit of I2C_CON be used with probing? */ dev->buf = msg->buf; dev->buf_len = msg->len; +wmb ();omap_i2c_write_reg (dev,OMAP_I2C_CNT_REG , dev->buf_len);@@ -579,7 +580,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,*/ timeout =wait_for_completion_timeout (&dev->cmd_complete,OMAP_I2C_TIMEOUT ); - dev->buf_len =0 ;if (timeout ==0 ) {dev_err (dev->dev,"controller timed out\n" );omap_i2c_init (dev);
PATCH 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
Hi,
Quoted 10 lines · Kevin Hilman
+Paul
Quoted 3 lines · Felipe Balbi
if we allow compiler reorder our writes, we could
fall into a situation wheredev->buf_lenis reset
for no apparent reason.Any chance this would help with the bug Paul found with I2C timeouts on beagle userspace startup?
I replied to the original thread asking the same ;-)
Signature · 8 lines
balbi -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121025/8550556d/attachment-0001.sig>
PATCH 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
In reply to Felipe BalbiHi Felipe
just two quick comments
Quoted 42 lines · Felipe Balbi
if we allow compiler reorder our writes, we could fall into a situation where
dev->buf_lenis reset for no apparent reason.This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size,
dev->buf_lenwas reset to zero before we had an oportunity to handle XDR Interrupt. Becausedev->buf_lenwas zero, we enteredomap_i2c_transmit_data()to transfer zero bytes, which would mean we would just silently exitomap_i2c_transmit_data()without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes.After adding the memory barrier, we also drop resetting
dev->buf_lento zero inomap_i2c_xfer_msg()because bothomap_i2c_transmit_data()andomap_i2c_receive_data()will act untildev->buf_lenreaches zero, rendering the other write inomap_i2c_xfer_msg()redundant.This patch has been tested with pandaboard for a few iterations of the script mentioned above.
Signed-off-by Felipe Balbi <[email protected]>---
This bug has been there forever, but it's quite annoying. I think it deserves being pushed upstream during this -rc cycle, but if Wolfram decides to wait until v3.8, I don't mind.
drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/i2c/busses/i2c-omap.c +0
-0
drivers/i2c/busses/i2c-omap.c static int omap_i2c_xfer_msg(struct i2c_adapter *adap, · line 527
Quoted 7 lines
drivers/i2c/busses/i2c-omap.c +1
-0@@ -521,6 +521,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,/* REVISIT: Could the STB bit of I2C_CON be used with probing? */ dev->buf = msg->buf; dev->buf_len = msg->len; +wmb ();omap_i2c_write_reg (dev,OMAP_I2C_CNT_REG , dev->buf_len);
Would suggest moving the wmb() immediately before the point at which the interrupt can occur. Looks to me that's when the OMAP_I2C_CON_REG write occurs.
Also would suggest adding a comment to clarify what the wmb() is intended to do. Maybe something like 'Prevent the compiler from moving earlier changes to dev->buf and dev->buf_len after the write to CON_REG. This write enables interrupts and those variables are used in the interrupt handler'.
checkpatch is supposed to flag uncommented barriers, but maybe that's only with --strict.
# check for memory barriers without a comment.
if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) {
if (!ctx_has_comment($first_line, $linenr)) {
CHK("MEMORY_BARRIER",
"memory barrier without comment\n" .
$herecurr);
}
}- Paul
PATCH 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
Quoted 60 lines · Paul Walmsley
Hi Felipe
just two quick comments
Quoted 42 lines · Felipe Balbi
if we allow compiler reorder our writes, we could fall into a situation where
dev->buf_lenis reset for no apparent reason.This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size,
dev->buf_lenwas reset to zero before we had an oportunity to handle XDR Interrupt. Becausedev->buf_lenwas zero, we enteredomap_i2c_transmit_data()to transfer zero bytes, which would mean we would just silently exitomap_i2c_transmit_data()without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes.After adding the memory barrier, we also drop resetting
dev->buf_lento zero inomap_i2c_xfer_msg()because bothomap_i2c_transmit_data()andomap_i2c_receive_data()will act untildev->buf_lenreaches zero, rendering the other write inomap_i2c_xfer_msg()redundant.This patch has been tested with pandaboard for a few iterations of the script mentioned above.
Signed-off-by Felipe Balbi <[email protected]>---
This bug has been there forever, but it's quite annoying. I think it deserves being pushed upstream during this -rc cycle, but if Wolfram decides to wait until v3.8, I don't mind.
drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/i2c/busses/i2c-omap.c +0
-0drivers/i2c/busses/i2c-omap.c static int omap_i2c_xfer_msg(struct i2c_adapter *adap, · line 527
Quoted 7 lines
drivers/i2c/busses/i2c-omap.c +1
-0@@ -521,6 +521,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,/* REVISIT: Could the STB bit of I2C_CON be used with probing? */ dev->buf = msg->buf; dev->buf_len = msg->len; +wmb ();omap_i2c_write_reg (dev,OMAP_I2C_CNT_REG , dev->buf_len);Would suggest moving the
wmb()immediately before the point at which the interrupt can occur. Looks to me that's when theOMAP_I2C_CON_REGwrite occurs.
Quoted 6 lines
Also would suggest adding a comment to clarify what the
wmb()is intended to do. Maybe something like 'Prevent the compiler from moving earlier changes todev->bufanddev->buf_lenafter the write toCON_REG. This write enables interrupts and those variables are used in the interrupt handler'.
Another alternative, which I will recommend to just make use of the read*/wrire* instead __raw versions. The barriers are taken care already and driver point of view, it is transparent.
-->
drivers/i2c/busses/i2c-omap.c +2 -2
@@ -265,13 +265,13 @@ static const u8 reg_map_ip_v2[] = {static inline void omap_i2c_write_reg (struct omap_i2c_dev *i2c_dev,int reg,u16 val) { -__raw_writew (val, i2c_dev->base + +writew (val, i2c_dev->base + (i2c_dev->regs[reg] << i2c_dev->reg_shift)); }static inline u16 omap_i2c_read_reg (struct omap_i2c_dev *i2c_dev,int reg) { -return __raw_readw (i2c_dev->base + +return readw (i2c_dev->base + (i2c_dev->regs[reg] << i2c_dev->reg_shift)); }
Patch might be damaged because of copy paste.
Regards
Santosh
PATCH 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
Quoted 3 lines · Santosh Shilimkar
Another alternative, which I will recommend to just make use of the read*/wrire* instead
__rawversions. The barriers are taken care already and driver point of view, it is transparent.
Those barriers will disappear if CONFIG_ARM_DMA_MEM_BUFFERABLE is set to N, so that's probably not the right thing to do in this case. The barrier here isn't DMA-related, it's needed due to the design of the driver.
In fact the wmb() is probably overkill, since only a compiler reordering barrier is needed. It can probably just be barrier().
- Paul
PATCH 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
Quoted 10 lines · Paul Walmsley
Quoted 3 lines · Santosh Shilimkar
Another alternative, which I will recommend to just make use of the read*/wrire* instead
__rawversions. The barriers are taken care already and driver point of view, it is transparent.Those barriers will disappear if
CONFIG_ARM_DMA_MEM_BUFFERABLEis set to N, so that's probably not the right thing to do in this case. The barrier here isn't DMA-related, it's needed due to the design of the driver.
Good point.
Quoted 3 lines
In fact the
wmb()is probably overkill, since only a compiler reordering barrier is needed. It can probably just bebarrier().
I agree. Just barrier() is enough to avoid compiler re-ordering.
Regards
Santosh
PATCH 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
In reply to Felipe BalbiQuoted 26 lines · Felipe Balbi
if we allow compiler reorder our writes, we could fall into a situation where
dev->buf_lenis reset for no apparent reason.This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size,
dev->buf_lenwas reset to zero before we had an oportunity to handle XDR Interrupt. Becausedev->buf_lenwas zero, we enteredomap_i2c_transmit_data()to transfer zero bytes, which would mean we would just silently exitomap_i2c_transmit_data()without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes.After adding the memory barrier, we also drop resetting
dev->buf_lento zero inomap_i2c_xfer_msg()because bothomap_i2c_transmit_data()andomap_i2c_receive_data()will act untildev->buf_lenreaches zero, rendering the other write inomap_i2c_xfer_msg()redundant.This patch has been tested with pandaboard for a few iterations of the script mentioned above.
Quoted 7 lines
Signed-off-by Felipe Balbi <[email protected]>---
This bug has been there forever, but it's quite annoying. I think it deserves being pushed upstream during this -rc cycle, but if Wolfram decides to wait until v3.8, I don't mind.
I would add this into 3.7, but what about the comments suggesting to use barrier()?
Signature · 9 lines
Pengutronix e.K. | Wolfram Sang | Industrial Linux Solutions | http://www.pengutronix.de/ | -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 198 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121101/928fba26/attachment.sig>
PATCH 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
Hi,
Quoted 30 lines · Wolfram Sang
Quoted 29 lines · Felipe Balbi
if we allow compiler reorder our writes, we could fall into a situation where
dev->buf_lenis reset for no apparent reason.This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size,
dev->buf_lenwas reset to zero before we had an oportunity to handle XDR Interrupt. Becausedev->buf_lenwas zero, we enteredomap_i2c_transmit_data()to transfer zero bytes, which would mean we would just silently exitomap_i2c_transmit_data()without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes.After adding the memory barrier, we also drop resetting
dev->buf_lento zero inomap_i2c_xfer_msg()because bothomap_i2c_transmit_data()andomap_i2c_receive_data()will act untildev->buf_lenreaches zero, rendering the other write inomap_i2c_xfer_msg()redundant.This patch has been tested with pandaboard for a few iterations of the script mentioned above.
Signed-off-by Felipe Balbi <[email protected]>---
Quoted 7 lines
Quoted 4 lines
This bug has been there forever, but it's quite annoying. I think it deserves being pushed upstream during this -rc cycle, but if Wolfram decides to wait until v3.8, I don't mind.
I would add this into 3.7, but what about the comments suggesting to use
barrier()?
I was waiting for more comments, will respin the patch next week.
cheers
Signature · 8 lines
balbi -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121102/1206e9bb/attachment.sig>
PATCH v2 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
if we allow compiler reorder our writes, we could fall into a situation where dev->buf_len is reset for no apparent reason.
This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size, dev->buf_len was reset to zero before we had an oportunity to handle XDR Interrupt. Because dev->buf_len was zero, we entered omap_i2c_transmit_data() to transfer zero bytes, which would mean we would just silently exit omap_i2c_transmit_data() without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes.
After adding the memory barrier, we also drop resetting dev->buf_len to zero in omap_i2c_xfer_msg() because both omap_i2c_transmit_data() and omap_i2c_receive_data() will act until dev->buf_len reaches zero, rendering the other write in omap_i2c_xfer_msg() redundant.
This patch has been tested with pandaboard for a few iterations of the script mentioned above.
---
Changes since v1:
- use barrier() instead of wmb()
Note: this version was compile-tested only
drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/i2c/busses/i2c-omap.c +1 -1
@@ -521,6 +521,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,/* REVISIT: Could the STB bit of I2C_CON be used with probing? */ dev->buf = msg->buf; dev->buf_len = msg->len; +barrier ();omap_i2c_write_reg (dev,OMAP_I2C_CNT_REG , dev->buf_len);
@@ -579,7 +580,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,*/ timeout =wait_for_completion_timeout (&dev->cmd_complete,OMAP_I2C_TIMEOUT ); - dev->buf_len =0 ;if (timeout ==0 ) {dev_err (dev->dev,"controller timed out\n" );omap_i2c_init (dev);
Signature · 1 line
1.8.0
PATCH v2 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
Quoted 42 lines · Felipe Balbi
if we allow compiler reorder our writes, we could fall into a situation where
dev->buf_lenis reset for no apparent reason.This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size,
dev->buf_lenwas reset to zero before we had an oportunity to handle XDR Interrupt. Becausedev->buf_lenwas zero, we enteredomap_i2c_transmit_data()to transfer zero bytes, which would mean we would just silently exitomap_i2c_transmit_data()without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes.After adding the memory barrier, we also drop resetting
dev->buf_lento zero inomap_i2c_xfer_msg()because bothomap_i2c_transmit_data()andomap_i2c_receive_data()will act untildev->buf_lenreaches zero, rendering the other write inomap_i2c_xfer_msg()redundant.This patch has been tested with pandaboard for a few iterations of the script mentioned above.
Signed-off-by Felipe Balbi <[email protected]>---
Changes since v1:
- usebarrier()instead ofwmb()Note: this version was compile-tested only
drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/i2c/busses/i2c-omap.c +0
-0
drivers/i2c/busses/i2c-omap.c static int omap_i2c_xfer_msg(struct i2c_adapter *adap, · line 524
Quoted 4 lines
drivers/i2c/busses/i2c-omap.c +1
-0@@ -521,6 +521,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,/* REVISIT: Could the STB bit of I2C_CON be used with probing? */ dev->buf = msg->buf; dev->buf_len = msg->len; +barrier ();
I agree adding a comment here is a good idea.
Signature · 9 lines
Pengutronix e.K. | Wolfram Sang | Industrial Linux Solutions | http://www.pengutronix.de/ | -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 198 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121114/5b44e45c/attachment.sig>
PATCH v3 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
if we allow compiler reorder our writes, we could fall into a situation where dev->buf_len is reset for no apparent reason.
This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size, dev->buf_len was reset to zero before we had an oportunity to handle XDR Interrupt. Because dev->buf_len was zero, we entered omap_i2c_transmit_data() to transfer zero bytes, which would mean we would just silently exit omap_i2c_transmit_data() without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes.
After adding the memory barrier, we also drop resetting dev->buf_len to zero in omap_i2c_xfer_msg() because both omap_i2c_transmit_data() and omap_i2c_receive_data() will act until dev->buf_len reaches zero, rendering the other write in omap_i2c_xfer_msg() redundant.
This patch has been tested with pandaboard for a few iterations of the script mentioned above.
---
Changes since v2:
- add a comment
Changes since v1:
- use barrier() instead of wmb()
drivers/i2c/busses/i2c-omap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/i2c/busses/i2c-omap.c +3 -1
@@ -522,6 +522,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, dev->buf = msg->buf; dev->buf_len = msg->len; +/* make sure writes to dev->buf_len are ordered */ +barrier (); +omap_i2c_write_reg (dev,OMAP_I2C_CNT_REG , dev->buf_len);/* Clear the FIFO Buffers */
@@ -579,7 +582,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,*/ timeout =wait_for_completion_timeout (&dev->cmd_complete,OMAP_I2C_TIMEOUT ); - dev->buf_len =0 ;if (timeout ==0 ) {dev_err (dev->dev,"controller timed out\n" );omap_i2c_init (dev);
Signature · 1 line
1.8.0
Wolfram Sang
AppliedPATCH v3 1/1 i2c: omap: ensure writes to dev->buf_len are ordered
Quoted 23 lines · Felipe Balbi
if we allow compiler reorder our writes, we could fall into a situation where
dev->buf_lenis reset for no apparent reason.This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size,
dev->buf_lenwas reset to zero before we had an oportunity to handle XDR Interrupt. Becausedev->buf_lenwas zero, we enteredomap_i2c_transmit_data()to transfer zero bytes, which would mean we would just silently exitomap_i2c_transmit_data()without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes.After adding the memory barrier, we also drop resetting
dev->buf_lento zero inomap_i2c_xfer_msg()because bothomap_i2c_transmit_data()andomap_i2c_receive_data()will act untildev->buf_lenreaches zero, rendering the other write inomap_i2c_xfer_msg()redundant.
Quoted 4 lines
This patch has been tested with pandaboard for a few iterations of the script mentioned above.
Signed-off-by Felipe Balbi <[email protected]>
Applied to for-current, thanks!
Signature · 9 lines
Pengutronix e.K. | Wolfram Sang | Industrial Linux Solutions | http://www.pengutronix.de/ | -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 198 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121114/0b0eb476/attachment.sig>