i2c-designware: fix RX FIFO overrun
Subsystems (3)
PATCH 1/1 i2c-designware: fix RX FIFO overrun
Quoted 1 line
From
a969728248c3b439dc97a69e7dac133b5efa34e7Mon Sep 17 00:00:00 2001
From: Josef Ahmad <[email protected]>
Date: Fri, 19 Apr 2013 17:28:10 +0100
Subject: [PATCH] i2c-designware: fix RX FIFO overrun
i2c_dw_xfer_msg() pushes a number of bytes to transmit/receive to/from the bus into the TX FIFO.
For master-rx transactions, the maximum amount of data that can be received is calculated depending solely on TX and RX FIFO load.
This is racy - TX FIFO may contain master-rx data yet to be processed, which will eventually land into the RX FIFO. This data is not taken into account and the function may request more data than the controller is actually capable of storing.
This patch ensures the driver takes into account the outstanding master-rx data in TX FIFO to prevent RX FIFO overrun.
--- drivers/i2c/busses/i2c-designware-core.c | 11 ++++++++++- drivers/i2c/busses/i2c-designware-core.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletions(-)
drivers/i2c/busses/i2c-designware-core.c +10 -1
@@ -426,8 +426,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) cmd |=BIT (9 );if (msgs[dev->msg_write_idx].flags &I2C_M_RD ) { + +/* avoid rx buffer overrun */ +if (rx_limit - dev->rx_outstanding <=0 ) +break ; +dw_writel (dev, cmd |0x100 ,DW_IC_DATA_CMD ); rx_limit--; + dev->rx_outstanding++; }else dw_writel (dev, cmd | *buf++,DW_IC_DATA_CMD ); tx_limit--; buf_len--;
@@ -480,8 +486,10 @@ i2c_dw_read(struct dw_i2c_dev *dev) rx_valid =dw_readl (dev,DW_IC_RXFLR ); -for (; len >0 && rx_valid >0 ; len--, rx_valid--) +for (; len >0 && rx_valid >0 ; len--, rx_valid--) { *buf++ =dw_readl (dev,DW_IC_DATA_CMD ); + dev->rx_outstanding--; + }if (len >0 ) { dev->status |=STATUS_READ_IN_PROGRESS ;
@@ -539,6 +547,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev->msg_err =0 ; dev->status =STATUS_IDLE ; dev->abort_source =0 ; + dev->rx_outstanding =0 ; ret =i2c_dw_wait_bus_not_busy (dev);if (ret <0 )
drivers/i2c/busses/i2c-designware-core.h +2 -0
@@ -60,6 +60,7 @@* @adapter: i2c subsystem adapter node * @tx_fifo_depth: depth of the hardware tx fifo * @rx_fifo_depth: depth of the hardware rx fifo +* @rx_outstanding: current master-rx elements in tx fifo */ struct dw_i2c_dev {struct device *dev;
@@ -88,6 +89,7 @@ struct dw_i2c_dev {u32 master_cfg;unsigned int tx_fifo_depth;unsigned int rx_fifo_depth; +int rx_outstanding; };#define ACCESS_SWAP 0x00000001
Signature · 1 line
1.7.0.7
Josef.
This fixes a real bug for us does it not, some failure case with a sustained amount of traffic ?
Bryan
It does.
The bug appears with fairly-sized read transactions (in the order of kB) returning corrupted data.
Josef
Quoted 9 lines
Josef.
This fixes a real bug for us does it not, some failure case with a sustained amount of traffic ?
Bryan
Mika Westerberg
maintainerQuoted 10 lines · Josef Ahmad
Quoted 1 line
From
a969728248c3b439dc97a69e7dac133b5efa34e7Mon Sep 17 00:00:00 2001From: Josef Ahmad <[email protected]>
Date: Fri, 19 Apr 2013 17:28:10 +0100
Subject: [PATCH] i2c-designware: fix RX FIFO overrun
i2c_dw_xfer_msg()pushes a number of bytes to transmit/receive to/from the bus into the TX FIFO.
For master-rx transactions, the maximum amount of data that can be received is calculated depending solely on TX and RX FIFO load.
Quoted 7 lines
This is racy - TX FIFO may contain master-rx data yet to be processed, which will eventually land into the RX FIFO. This data is not taken into account and the function may request more data than the controller is actually capable of storing.
This patch ensures the driver takes into account the outstanding master-rx data in TX FIFO to prevent RX FIFO overrun.
Can you add something to the changelog to show what the error looks like (a dump from dmesg for example)?
Quoted 12 lines
Signed-off-by Josef Ahmad <[email protected]>--- drivers/i2c/busses/i2c-designware-core.c | 11 ++++++++++- drivers/i2c/busses/i2c-designware-core.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletions(-)drivers/i2c/busses/i2c-designware-core.c +0
-0@@ -426,8 +426,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) cmd |=BIT (9 );
drivers/i2c/busses/i2c-designware-core.c i2c_dw_xfer_msg(struct dw_i2c_dev *dev) · line 436
Quoted 10 lines
drivers/i2c/busses/i2c-designware-core.c +6
-0if (msgs[dev->msg_write_idx].flags &I2C_M_RD ) { + +/* avoid rx buffer overrun */ +if (rx_limit - dev->rx_outstanding <=0 ) +break ; +dw_writel (dev, cmd |0x100 ,DW_IC_DATA_CMD ); rx_limit--; + dev->rx_outstanding++;
Instead of adding a new variable, is there something preventing a use of DW_IC_STATUS bits RFNE and TFNF?
Quoted 23 lines
drivers/i2c/busses/i2c-designware-core.c +4
-1}else dw_writel (dev, cmd | *buf++,DW_IC_DATA_CMD ); tx_limit--; buf_len--;@@ -480,8 +486,10 @@ i2c_dw_read(struct dw_i2c_dev *dev) rx_valid =dw_readl (dev,DW_IC_RXFLR ); -for (; len >0 && rx_valid >0 ; len--, rx_valid--) +for (; len >0 && rx_valid >0 ; len--, rx_valid--) { *buf++ =dw_readl (dev,DW_IC_DATA_CMD ); + dev->rx_outstanding--; + }if (len >0 ) { dev->status |=STATUS_READ_IN_PROGRESS ;@@ -539,6 +547,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev->msg_err =0 ; dev->status =STATUS_IDLE ; dev->abort_source =0 ; + dev->rx_outstanding =0 ; ret =i2c_dw_wait_bus_not_busy (dev);if (ret <0 )
Quoted 16 lines · Josef Ahmad
Quoted 15 lines
Quoted 1 line
From
a969728248c3b439dc97a69e7dac133b5efa34e7Mon Sep 17 00:00:00 2001From: Josef Ahmad <josef.ahmad-VuQAYsv1563Yd54FQh9/[email protected]>
Date: Fri, 19 Apr 2013 17:28:10 +0100
Subject: [PATCH] i2c-designware: fix RX FIFO overrun
i2c_dw_xfer_msg()pushes a number of bytes to transmit/receive to/from the bus into the TX FIFO.
For master-rx transactions, the maximum amount of data that can be received is calculated depending solely on TX and RX FIFO load.This is racy - TX FIFO may contain master-rx data yet to be processed, which will eventually land into the RX FIFO. This data is not taken into account and the function may request more data than the controller is actually capable of storing.
Quoted 6 lines
Quoted 2 lines
This patch ensures the driver takes into account the outstanding master-rx data in TX FIFO to prevent RX FIFO overrun.
Can you add something to the changelog to show what the error looks like (a dump from dmesg for example)?
The issue is, the data is silently corrupted and not notified to the I2C core driver.
The master-rx transaction returns success and the RX buffer overflow is not reported by the driver, which will read dropped data.
FWIW, I have a simple test application receiving well-known data from a slave in a single transaction, and comparing received to expected data. Here's the outcome of three runs:
[19/03/13 20:30:14] i2c-error : rcv'd message != ref msg (first diff
@byte 33)
[19/03/13 20:30:43] i2c-error : rcv'd message != ref msg (first diff
@byte 108)
[19/03/13 20:31:24] i2c-error : rcv'd message != ref msg (first diff
@byte 133)
Quoted 14 lines
Quoted 14 lines
--- drivers/i2c/busses/i2c-designware-core.c | 11 ++++++++++- drivers/i2c/busses/i2c-designware-core.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletions(-)drivers/i2c/busses/i2c-designware-core.c +0
-0@@ -426,8 +426,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) cmd |=BIT (9 );
Quoted 13 lines
drivers/i2c/busses/i2c-designware-core.c i2c_dw_xfer_msg(struct dw_i2c_dev *dev) · line 436
Quoted 9 lines
drivers/i2c/busses/i2c-designware-core.c +6
-0if (msgs[dev->msg_write_idx].flags &I2C_M_RD ) { + +/* avoid rx buffer overrun */ +if (rx_limit - dev->rx_outstanding <=0 ) +break ; +dw_writel (dev, cmd |0x100 ,DW_IC_DATA_CMD ); rx_limit--; + dev->rx_outstanding++;Instead of adding a new variable, is there something preventing a use of
DW_IC_STATUSbits RFNE and TFNF?
DW_IC_STATUS bits won't give information of the type of elements (read or write) that are in the fifos.
What we need here is more specific information, i.e. how many RX elements are currently in TX fifo. The register set doesn't provide this information to my knowledge, so I had to work it out externally with a status variable.
Consider this example with 8-byte fifos (E=empty, R=read, W=write elements):
State of the fifos:
+-----------------+
TX -> | E E E E E W W R |
+-----------------+
+-----------------+
RX | E E R R R R R R | <-
+-----------------+Now, say the transaction requires to pump 2 additional R elements into TX fifo. We need to ensure that at this stage only 1 of the 2 R elements is actually put into TX fifo: this way we we won't saturate the RX fifo. Failing to do so exposes a race condition: if we don't read RX quickly enough,
the R element + the new 2 R elements in the TX fifo will land into the RX, resulting in an element being dropped.
Quoted 25 lines
Quoted 24 lines
drivers/i2c/busses/i2c-designware-core.c +4
-1}else dw_writel (dev, cmd | *buf++,DW_IC_DATA_CMD ); tx_limit--; buf_len--;@@ -480,8 +486,10 @@ i2c_dw_read(struct dw_i2c_dev *dev) rx_valid =dw_readl (dev,DW_IC_RXFLR ); -for (; len >0 && rx_valid >0 ; len--, rx_valid--) +for (; len >0 && rx_valid >0 ; len--, rx_valid--) { *buf++ =dw_readl (dev,DW_IC_DATA_CMD ); + dev->rx_outstanding--; + }if (len >0 ) { dev->status |=STATUS_READ_IN_PROGRESS ;@@ -539,6 +547,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev->msg_err =0 ; dev->status =STATUS_IDLE ; dev->abort_source =0 ; + dev->rx_outstanding =0 ; ret =i2c_dw_wait_bus_not_busy (dev);if (ret < 0)
Quoted 19 lines · Josef Ahmad
Quoted 19 lines · Josef Ahmad
Quoted 17 lines
Quoted 1 line
From
a969728248c3b439dc97a69e7dac133b5efa34e7Mon Sep 17 00:00:00 2001From: Josef Ahmad <[email protected]>
Date: Fri, 19 Apr 2013 17:28:10 +0100
Subject: [PATCH] i2c-designware: fix RX FIFO overrun
i2c_dw_xfer_msg()pushes a number of bytes to transmit/receive to/from the bus into the TX FIFO.
For master-rx transactions, the maximum amount of data that can be received is calculated depending solely on TX and RX FIFO load.This is racy - TX FIFO may contain master-rx data yet to be processed, which will eventually land into the RX FIFO. This data is not taken into account and the function may request more data than the controller is actually capable of storing.
This patch ensures the driver takes into account the outstanding master-rx data in TX FIFO to prevent RX FIFO overrun.
Quoted 8 lines
Quoted 3 lines
Can you add something to the changelog to show what the error looks like (a dump from dmesg for example)?
The issue is, the data is silently corrupted and not notified to the I2C core driver.
The master-rx transaction returns success and the RX buffer overflow is not reported by the driver, which will read dropped data.
OK.
Quoted 55 lines
FWIW, I have a simple test application receiving well-known data from a slave in a single transaction, and comparing received to expected data. Here's the outcome of three runs:
[19/03/13 20:30:14] i2c-error : rcv'd message != ref msg (first diff
@byte 33)
[19/03/13 20:30:43] i2c-error : rcv'd message != ref msg (first diff
@byte 108)
[19/03/13 20:31:24] i2c-error : rcv'd message != ref msg (first diff
@byte 133)Quoted 14 lines
Quoted 14 lines
Signed-off-by Josef Ahmad <[email protected]>--- drivers/i2c/busses/i2c-designware-core.c | 11 ++++++++++- drivers/i2c/busses/i2c-designware-core.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletions(-)drivers/i2c/busses/i2c-designware-core.c +0
-0@@ -426,8 +426,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) cmd |=BIT (9 );Quoted 13 lines
drivers/i2c/busses/i2c-designware-core.c i2c_dw_xfer_msg(struct dw_i2c_dev *dev) · line 436
Quoted 9 lines
drivers/i2c/busses/i2c-designware-core.c +6
-0if (msgs[dev->msg_write_idx].flags &I2C_M_RD ) { + +/* avoid rx buffer overrun */ +if (rx_limit - dev->rx_outstanding <=0 ) +break ; +dw_writel (dev, cmd |0x100 ,DW_IC_DATA_CMD ); rx_limit--; + dev->rx_outstanding++;Instead of adding a new variable, is there something preventing a use of
DW_IC_STATUSbits RFNE and TFNF?
DW_IC_STATUSbits won't give information of the type of elements (read or write) that are in the fifos.
What we need here is more specific information, i.e. how many RX elements are currently in TX fifo. The register set doesn't provide this information to my knowledge, so I had to work it out externally with a status variable.Consider this example with 8-byte fifos (E=empty, R=read, W=write elements):
State of the fifos:
+-----------------+ TX -> | E E E E E W W R | +-----------------+ +-----------------+ RX | E E R R R R R R | <- +-----------------+
Quoted 7 lines
Now, say the transaction requires to pump 2 additional R elements into TX fifo. We need to ensure that at this stage only 1 of the 2 R elements is actually put into TX fifo: this way we we won't saturate the RX fifo. Failing to do so exposes a race condition: if we don't read RX quickly enough,
the R element + the new 2 R elements in the TX fifo will land into the RX, resulting in an element being dropped.
Thanks for the explanation. Makes sense to me now.
Feel free to add my
Josef Ahmad
Acked-by Mika WesterbergQuoted 1 line
From
a969728248c3b439dc97a69e7dac133b5efa34e7Mon Sep 17 00:00:00 2001
From: Josef Ahmad <josef.ahmad-VuQAYsv1563Yd54FQh9/[email protected]>
Date: Fri, 19 Apr 2013 17:28:10 +0100
Subject: [PATCH] i2c-designware: fix RX FIFO overrun
i2c_dw_xfer_msg() pushes a number of bytes to transmit/receive to/from the bus into the TX FIFO.
For master-rx transactions, the maximum amount of data that can be received is calculated depending solely on TX and RX FIFO load.
This is racy - TX FIFO may contain master-rx data yet to be processed, which will eventually land into the RX FIFO. This data is not taken into account and the function may request more data than the controller is actually capable of storing.
This patch ensures the driver takes into account the outstanding master-rx data in TX FIFO to prevent RX FIFO overrun.
--- drivers/i2c/busses/i2c-designware-core.c | 11 ++++++++++- drivers/i2c/busses/i2c-designware-core.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletions(-)
drivers/i2c/busses/i2c-designware-core.c +10 -1
@@ -426,8 +426,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) cmd |=BIT (9 );if (msgs[dev->msg_write_idx].flags &I2C_M_RD ) { + +/* avoid rx buffer overrun */ +if (rx_limit - dev->rx_outstanding <=0 ) +break ; +dw_writel (dev, cmd |0x100 ,DW_IC_DATA_CMD ); rx_limit--; + dev->rx_outstanding++; }else dw_writel (dev, cmd | *buf++,DW_IC_DATA_CMD ); tx_limit--; buf_len--;
@@ -480,8 +486,10 @@ i2c_dw_read(struct dw_i2c_dev *dev) rx_valid =dw_readl (dev,DW_IC_RXFLR ); -for (; len >0 && rx_valid >0 ; len--, rx_valid--) +for (; len >0 && rx_valid >0 ; len--, rx_valid--) { *buf++ =dw_readl (dev,DW_IC_DATA_CMD ); + dev->rx_outstanding--; + }if (len >0 ) { dev->status |=STATUS_READ_IN_PROGRESS ;
@@ -539,6 +547,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev->msg_err =0 ; dev->status =STATUS_IDLE ; dev->abort_source =0 ; + dev->rx_outstanding =0 ; ret =i2c_dw_wait_bus_not_busy (dev);if (ret <0 )
drivers/i2c/busses/i2c-designware-core.h +2 -0
@@ -60,6 +60,7 @@* @adapter: i2c subsystem adapter node * @tx_fifo_depth: depth of the hardware tx fifo * @rx_fifo_depth: depth of the hardware rx fifo +* @rx_outstanding: current master-rx elements in tx fifo */ struct dw_i2c_dev {struct device *dev;
@@ -88,6 +89,7 @@ struct dw_i2c_dev {u32 master_cfg;unsigned int tx_fifo_depth;unsigned int rx_fifo_depth; +int rx_outstanding; };#define ACCESS_SWAP 0x00000001
Signature · 1 line
1.7.0.7
Quoted 15 lines · Josef Ahmad
From
a969728248c3b439dc97a69e7dac133b5efa34e7Mon Sep 17 00:00:00 2001
From: Josef Ahmad <josef.ahmad-VuQAYsv1563Yd54FQh9/[email protected]>
Date: Fri, 19 Apr 2013 17:28:10 +0100
Subject: [PATCH] i2c-designware: fix RX FIFO overrun
i2c_dw_xfer_msg()pushes a number of bytes to transmit/receive to/from the bus into the TX FIFO.
For master-rx transactions, the maximum amount of data that can be received is calculated depending solely on TX and RX FIFO load.This is racy - TX FIFO may contain master-rx data yet to be processed, which will eventually land into the RX FIFO. This data is not taken into account and the function may request more data than the controller is actually capable of storing.
Quoted 5 lines
This patch ensures the driver takes into account the outstanding master-rx data in TX FIFO to prevent RX FIFO overrun.
This driver had a major cleanup meanwhile. Could you rebase your patch on top of my for-next branch? I guess this version should make it into stable?
Quoted 19 lines · Josef Ahmad
Quoted 18 lines
From
a969728248c3b439dc97a69e7dac133b5efa34e7Mon Sep 17 00:00:00 2001
From: Josef Ahmad <josef.ahmad-VuQAYsv1563Yd54FQh9/[email protected]>
Date: Fri, 19 Apr 2013 17:28:10 +0100
Subject: [PATCH] i2c-designware: fix RX FIFO overrun
i2c_dw_xfer_msg()pushes a number of bytes to transmit/receive to/from the bus into the TX FIFO.
For master-rx transactions, the maximum amount of data that can be received is calculated depending solely on TX and RX FIFO load.This is racy - TX FIFO may contain master-rx data yet to be processed, which will eventually land into the RX FIFO. This data is not taken into account and the function may request more data than the controller is actually capable of storing.
This patch ensures the driver takes into account the outstanding master-rx data in TX FIFO to prevent RX FIFO overrun.
Quoted 7 lines
Quoted 2 lines
This driver had a major cleanup meanwhile. Could you rebase your patch on top of my for-next branch? I guess this version should make it into stable?
Hi Wolfram
This patch applies just fine on top of your i2c-embedded/for-next branch.
Quoted 7 lines
Quoted 5 lines
This driver had a major cleanup meanwhile. Could you rebase your patch on top of my for-next branch? I guess this version should make it into stable?
This patch applies just fine on top of your i2c-embedded/for-next branch.
i2c-embedded? Ah, this one is outdated. Please checkgit://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/for-next.
Thanks,
Wolfram
Josef Ahmad
Acked-by Mika WesterbergQuoted 1 line
From
8a4773d0c0df6fe2e816ad37fde30a2d90a1ad31Mon Sep 17 00:00:00 2001
From: Josef Ahmad <josef.ahmad-VuQAYsv1563Yd54FQh9/[email protected]>
Date: Fri, 19 Apr 2013 17:28:10 +0100
Subject: [PATCH] i2c-designware: fix RX FIFO overrun
i2c_dw_xfer_msg() pushes a number of bytes to transmit/receive to/from the bus into the TX FIFO.
For master-rx transactions, the maximum amount of data that can be received is calculated depending solely on TX and RX FIFO load.
This is racy - TX FIFO may contain master-rx data yet to be processed, which will eventually land into the RX FIFO. This data is not taken into account and the function may request more data than the controller is actually capable of storing.
This patch ensures the driver takes into account the outstanding master-rx data in TX FIFO to prevent RX FIFO overrun.
--- drivers/i2c/busses/i2c-designware-core.c | 11 ++++++++++- drivers/i2c/busses/i2c-designware-core.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletions(-)
drivers/i2c/busses/i2c-designware-core.c +10 -1
@@ -448,8 +448,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) cmd |=BIT (9 );if (msgs[dev->msg_write_idx].flags &I2C_M_RD ) { + +/* avoid rx buffer overrun */ +if (rx_limit - dev->rx_outstanding <=0 ) +break ; +dw_writel (dev, cmd |0x100 ,DW_IC_DATA_CMD ); rx_limit--; + dev->rx_outstanding++; }else dw_writel (dev, cmd | *buf++,DW_IC_DATA_CMD ); tx_limit--; buf_len--;
@@ -502,8 +508,10 @@ i2c_dw_read(struct dw_i2c_dev *dev) rx_valid =dw_readl (dev,DW_IC_RXFLR ); -for (; len >0 && rx_valid >0 ; len--, rx_valid--) +for (; len >0 && rx_valid >0 ; len--, rx_valid--) { *buf++ =dw_readl (dev,DW_IC_DATA_CMD ); + dev->rx_outstanding--; + }if (len >0 ) { dev->status |=STATUS_READ_IN_PROGRESS ;
@@ -561,6 +569,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev->msg_err =0 ; dev->status =STATUS_IDLE ; dev->abort_source =0 ; + dev->rx_outstanding =0 ; ret =i2c_dw_wait_bus_not_busy (dev);if (ret <0 )
drivers/i2c/busses/i2c-designware-core.h +2 -0
@@ -60,6 +60,7 @@* @adapter: i2c subsystem adapter node * @tx_fifo_depth: depth of the hardware tx fifo * @rx_fifo_depth: depth of the hardware rx fifo +* @rx_outstanding: current master-rx elements in tx fifo */ struct dw_i2c_dev {struct device *dev;
@@ -88,6 +89,7 @@ struct dw_i2c_dev {u32 master_cfg;unsigned int tx_fifo_depth;unsigned int rx_fifo_depth; +int rx_outstanding; };#define ACCESS_SWAP 0x00000001
Signature · 1 line
1.7.0.7
Quoted 15 lines · Josef Ahmad
From
8a4773d0c0df6fe2e816ad37fde30a2d90a1ad31Mon Sep 17 00:00:00 2001
From: Josef Ahmad <josef.ahmad-VuQAYsv1563Yd54FQh9/[email protected]>
Date: Fri, 19 Apr 2013 17:28:10 +0100
Subject: [PATCH] i2c-designware: fix RX FIFO overrun
i2c_dw_xfer_msg()pushes a number of bytes to transmit/receive to/from the bus into the TX FIFO.
For master-rx transactions, the maximum amount of data that can be received is calculated depending solely on TX and RX FIFO load.This is racy - TX FIFO may contain master-rx data yet to be processed, which will eventually land into the RX FIFO. This data is not taken into account and the function may request more data than the controller is actually capable of storing.
Quoted 5 lines
This patch ensures the driver takes into account the outstanding master-rx data in TX FIFO to prevent RX FIFO overrun.
Still can't apply :( Whitespace problems in the patch context :(
Sorry for late reply.
Bad UA configuration. Will resend straight away.
Thanks,
Josef
Quoted 3 lines · Wolfram Sang
Still can't apply :( Whitespace problems in the patch context :(
Josef Ahmad
Acked-by Mika WesterbergQuoted 1 line
From
8a4773d0c0df6fe2e816ad37fde30a2d90a1ad31Mon Sep 17 00:00:00 2001
From: Josef Ahmad <[email protected]>
Date: Fri, 19 Apr 2013 17:28:10 +0100
Subject: [PATCH] i2c-designware: fix RX FIFO overrun
i2c_dw_xfer_msg() pushes a number of bytes to transmit/receive to/from the bus into the TX FIFO.
For master-rx transactions, the maximum amount of data that can be received is calculated depending solely on TX and RX FIFO load.
This is racy - TX FIFO may contain master-rx data yet to be processed, which will eventually land into the RX FIFO. This data is not taken into account and the function may request more data than the controller is actually capable of storing.
This patch ensures the driver takes into account the outstanding master-rx data in TX FIFO to prevent RX FIFO overrun.
--- drivers/i2c/busses/i2c-designware-core.c | 11 ++++++++++- drivers/i2c/busses/i2c-designware-core.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletions(-)
drivers/i2c/busses/i2c-designware-core.c +10 -1
@@ -448,8 +448,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) cmd |=BIT (9 );if (msgs[dev->msg_write_idx].flags &I2C_M_RD ) { + +/* avoid rx buffer overrun */ +if (rx_limit - dev->rx_outstanding <=0 ) +break ; +dw_writel (dev, cmd |0x100 ,DW_IC_DATA_CMD ); rx_limit--; + dev->rx_outstanding++; }else dw_writel (dev, cmd | *buf++,DW_IC_DATA_CMD ); tx_limit--; buf_len--;
@@ -502,8 +508,10 @@ i2c_dw_read(struct dw_i2c_dev *dev) rx_valid =dw_readl (dev,DW_IC_RXFLR ); -for (; len >0 && rx_valid >0 ; len--, rx_valid--) +for (; len >0 && rx_valid >0 ; len--, rx_valid--) { *buf++ =dw_readl (dev,DW_IC_DATA_CMD ); + dev->rx_outstanding--; + }if (len >0 ) { dev->status |=STATUS_READ_IN_PROGRESS ;
@@ -561,6 +569,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev->msg_err =0 ; dev->status =STATUS_IDLE ; dev->abort_source =0 ; + dev->rx_outstanding =0 ; ret =i2c_dw_wait_bus_not_busy (dev);if (ret <0 )
drivers/i2c/busses/i2c-designware-core.h +2 -0
@@ -60,6 +60,7 @@* @adapter: i2c subsystem adapter node * @tx_fifo_depth: depth of the hardware tx fifo * @rx_fifo_depth: depth of the hardware rx fifo +* @rx_outstanding: current master-rx elements in tx fifo */ struct dw_i2c_dev {struct device *dev;
@@ -88,6 +89,7 @@ struct dw_i2c_dev {u32 master_cfg;unsigned int tx_fifo_depth;unsigned int rx_fifo_depth; +int rx_outstanding; };#define ACCESS_SWAP 0x00000001
Signature · 1 line
1.7.0.7
Wolfram Sang
AppliedQuoted 15 lines · Josef Ahmad
From
8a4773d0c0df6fe2e816ad37fde30a2d90a1ad31Mon Sep 17 00:00:00 2001
From: Josef Ahmad <[email protected]>
Date: Fri, 19 Apr 2013 17:28:10 +0100
Subject: [PATCH] i2c-designware: fix RX FIFO overrun
i2c_dw_xfer_msg()pushes a number of bytes to transmit/receive to/from the bus into the TX FIFO.
For master-rx transactions, the maximum amount of data that can be received is calculated depending solely on TX and RX FIFO load.This is racy - TX FIFO may contain master-rx data yet to be processed, which will eventually land into the RX FIFO. This data is not taken into account and the function may request more data than the controller is actually capable of storing.
Quoted 5 lines
This patch ensures the driver takes into account the outstanding master-rx data in TX FIFO to prevent RX FIFO overrun.
Signed-off-by Josef Ahmad <[email protected]>Acked-by Mika Westerberg <[email protected]>
Applied to for-current, thanks!
Quoted 1 line
Applied to for-current, thanks!
Added stable, too.
Quoted 4 lines
Quoted 1 line
Applied to for-current, thanks!
Added stable, too.
Thanks Wolfram.