* [PATCH 1/4] i2c: imx: Fix reinit_completion() use
[not found] <20180523095623.3347-1-esben.haabendal@gmail.com>
@ 2018-05-23 9:56 ` Esben Haabendal
2018-07-04 7:03 ` Uwe Kleine-König
2018-05-23 9:56 ` [PATCH 2/4] i2c: imx: Fix race condition in dma read Esben Haabendal
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Esben Haabendal @ 2018-05-23 9:56 UTC (permalink / raw)
To: linux-i2c
Cc: Esben Haabendal, Wolfram Sang, Uwe Kleine-König, Phil Reid,
Philipp Zabel, Lucas Stach, Clemens Gruber,
Michail Georgios Etairidis, linux-kernel
From: Esben Haabendal <eha@deif.com>
Make sure to call reinit_completion() before dma is started to avoid race
condition where reinit_compleition() is called after complete() and before
wait_for_completion_timeout().
Signed-off-by: Esben Haabendal <eha@deif.com>
---
drivers/i2c/busses/i2c-imx.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index d7267dd9c7bf..6fca5e64cffb 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -377,6 +377,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
goto err_desc;
}
+ reinit_completion(&dma->cmd_complete);
txdesc->callback = i2c_imx_dma_callback;
txdesc->callback_param = i2c_imx;
if (dma_submit_error(dmaengine_submit(txdesc))) {
@@ -631,7 +632,6 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
* The first byte must be transmitted by the CPU.
*/
imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
- reinit_completion(&i2c_imx->dma->cmd_complete);
time_left = wait_for_completion_timeout(
&i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT));
@@ -690,7 +690,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
if (result)
return result;
- reinit_completion(&i2c_imx->dma->cmd_complete);
time_left = wait_for_completion_timeout(
&i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT));
--
2.17.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/4] i2c: imx: Fix reinit_completion() use
2018-05-23 9:56 ` [PATCH 1/4] i2c: imx: Fix reinit_completion() use Esben Haabendal
@ 2018-07-04 7:03 ` Uwe Kleine-König
2018-07-09 9:20 ` Esben Haabendal
0 siblings, 1 reply; 8+ messages in thread
From: Uwe Kleine-König @ 2018-07-04 7:03 UTC (permalink / raw)
To: Esben Haabendal
Cc: linux-i2c, Esben Haabendal, Wolfram Sang, Phil Reid,
Philipp Zabel, Lucas Stach, Clemens Gruber,
Michail Georgios Etairidis, linux-kernel, Yuan Yao, linux-imx
Cc += Yuan Yao who authored DMA support and the NXP team.
On Wed, May 23, 2018 at 11:56:20AM +0200, Esben Haabendal wrote:
> From: Esben Haabendal <eha@deif.com>
>
> Make sure to call reinit_completion() before dma is started to avoid race
> condition where reinit_compleition() is called after complete() and before
s/compleition/completion/
> wait_for_completion_timeout().
Is this a theoretical problem, or did it trigger on your side?
> Signed-off-by: Esben Haabendal <eha@deif.com>
Fixes: ce1a78840ff7 ("i2c: imx: add DMA support for freescale i2c driver")
Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
> drivers/i2c/busses/i2c-imx.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
> index d7267dd9c7bf..6fca5e64cffb 100644
> --- a/drivers/i2c/busses/i2c-imx.c
> +++ b/drivers/i2c/busses/i2c-imx.c
> @@ -377,6 +377,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
> goto err_desc;
> }
>
> + reinit_completion(&dma->cmd_complete);
> txdesc->callback = i2c_imx_dma_callback;
> txdesc->callback_param = i2c_imx;
> if (dma_submit_error(dmaengine_submit(txdesc))) {
> @@ -631,7 +632,6 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
> * The first byte must be transmitted by the CPU.
> */
> imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
> - reinit_completion(&i2c_imx->dma->cmd_complete);
> time_left = wait_for_completion_timeout(
> &i2c_imx->dma->cmd_complete,
> msecs_to_jiffies(DMA_TIMEOUT));
> @@ -690,7 +690,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
> if (result)
> return result;
>
> - reinit_completion(&i2c_imx->dma->cmd_complete);
> time_left = wait_for_completion_timeout(
> &i2c_imx->dma->cmd_complete,
> msecs_to_jiffies(DMA_TIMEOUT));
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/4] i2c: imx: Fix reinit_completion() use
2018-07-04 7:03 ` Uwe Kleine-König
@ 2018-07-09 9:20 ` Esben Haabendal
0 siblings, 0 replies; 8+ messages in thread
From: Esben Haabendal @ 2018-07-09 9:20 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: linux-i2c, Wolfram Sang, Phil Reid, Philipp Zabel, Lucas Stach,
Clemens Gruber, Michail Georgios Etairidis, linux-kernel,
Yuan Yao, linux-imx
Uwe Kleine-König <u.kleine-koenig@pengutronix.de> writes:
> Cc += Yuan Yao who authored DMA support and the NXP team.
>
> On Wed, May 23, 2018 at 11:56:20AM +0200, Esben Haabendal wrote:
>> From: Esben Haabendal <eha@deif.com>
>>
>> Make sure to call reinit_completion() before dma is started to avoid race
>> condition where reinit_compleition() is called after complete() and before
>
> s/compleition/completion/
Will fix in v2.
>
>> wait_for_completion_timeout().
>
> Is this a theoretical problem, or did it trigger on your side?
I thought I did trigger it, but haven't been able to reproduce.
So it might or might not be theoretical based on my experiences, but it
does look like something that can (and thus should) trigger sometimes.
/Esben
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/4] i2c: imx: Fix race condition in dma read
[not found] <20180523095623.3347-1-esben.haabendal@gmail.com>
2018-05-23 9:56 ` [PATCH 1/4] i2c: imx: Fix reinit_completion() use Esben Haabendal
@ 2018-05-23 9:56 ` Esben Haabendal
2018-07-05 6:32 ` Uwe Kleine-König
2018-05-23 9:56 ` [PATCH 3/4] i2c: imx: Simplify stopped state tracking Esben Haabendal
2018-05-23 9:56 ` [PATCH 4/4] arm: dts: ls1021a: Enable I2C DMA support Esben Haabendal
3 siblings, 1 reply; 8+ messages in thread
From: Esben Haabendal @ 2018-05-23 9:56 UTC (permalink / raw)
To: linux-i2c
Cc: Esben Haabendal, Wolfram Sang, Uwe Kleine-König,
Lucas Stach, Phil Reid, Linus Walleij, Clemens Gruber,
Wei Jinhua, Michail Georgios Etairidis, linux-kernel
From: Esben Haabendal <eha@deif.com>
This fixes a race condition, where the DMAEN bit ends up being set after
I2C slave has transmitted a byte following the dummy read. When that
happens, an interrupt is generated instead, and no DMA request is generated
to kickstart the DMA read, and a timeout happens after DMA_TIMEOUT (1 sec).
Fixed by setting the DMAEN bit before the dummy read.
Signed-off-by: Esben Haabendal <eha@deif.com>
---
drivers/i2c/busses/i2c-imx.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 6fca5e64cffb..742b548437af 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -677,9 +677,6 @@ 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;
- temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
- temp |= I2CR_DMAEN;
- imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
dma->chan_using = dma->chan_rx;
dma->dma_transfer_dir = DMA_DEV_TO_MEM;
@@ -819,6 +816,11 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
if ((msgs->len - 1) || block_data)
temp &= ~I2CR_TXAK;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ if (i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data) {
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ 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__);
--
2.17.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/4] i2c: imx: Fix race condition in dma read
2018-05-23 9:56 ` [PATCH 2/4] i2c: imx: Fix race condition in dma read Esben Haabendal
@ 2018-07-05 6:32 ` Uwe Kleine-König
2018-07-09 9:22 ` Esben Haabendal
0 siblings, 1 reply; 8+ messages in thread
From: Uwe Kleine-König @ 2018-07-05 6:32 UTC (permalink / raw)
To: Esben Haabendal
Cc: linux-i2c, Esben Haabendal, Wolfram Sang, Lucas Stach, Phil Reid,
Linus Walleij, Clemens Gruber, Wei Jinhua,
Michail Georgios Etairidis, linux-kernel
On Wed, May 23, 2018 at 11:56:21AM +0200, Esben Haabendal wrote:
> From: Esben Haabendal <eha@deif.com>
>
> This fixes a race condition, where the DMAEN bit ends up being set after
> I2C slave has transmitted a byte following the dummy read. When that
> happens, an interrupt is generated instead, and no DMA request is generated
> to kickstart the DMA read, and a timeout happens after DMA_TIMEOUT (1 sec).
>
> Fixed by setting the DMAEN bit before the dummy read.
Does this fix the problem or just narrow the race window?
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/4] i2c: imx: Fix race condition in dma read
2018-07-05 6:32 ` Uwe Kleine-König
@ 2018-07-09 9:22 ` Esben Haabendal
0 siblings, 0 replies; 8+ messages in thread
From: Esben Haabendal @ 2018-07-09 9:22 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: linux-i2c, Wolfram Sang, Lucas Stach, Phil Reid, Linus Walleij,
Clemens Gruber, Wei Jinhua, Michail Georgios Etairidis,
linux-kernel
Uwe Kleine-König <u.kleine-koenig@pengutronix.de> writes:
> On Wed, May 23, 2018 at 11:56:21AM +0200, Esben Haabendal wrote:
>> From: Esben Haabendal <eha@deif.com>
>>
>> This fixes a race condition, where the DMAEN bit ends up being set after
>> I2C slave has transmitted a byte following the dummy read. When that
>> happens, an interrupt is generated instead, and no DMA request is generated
>> to kickstart the DMA read, and a timeout happens after DMA_TIMEOUT (1 sec).
>>
>> Fixed by setting the DMAEN bit before the dummy read.
>
> Does this fix the problem or just narrow the race window?
It should fix the problem.
/Esben
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/4] i2c: imx: Simplify stopped state tracking
[not found] <20180523095623.3347-1-esben.haabendal@gmail.com>
2018-05-23 9:56 ` [PATCH 1/4] i2c: imx: Fix reinit_completion() use Esben Haabendal
2018-05-23 9:56 ` [PATCH 2/4] i2c: imx: Fix race condition in dma read Esben Haabendal
@ 2018-05-23 9:56 ` Esben Haabendal
2018-05-23 9:56 ` [PATCH 4/4] arm: dts: ls1021a: Enable I2C DMA support Esben Haabendal
3 siblings, 0 replies; 8+ messages in thread
From: Esben Haabendal @ 2018-05-23 9:56 UTC (permalink / raw)
To: linux-i2c
Cc: Esben Haabendal, Wolfram Sang, Uwe Kleine-König,
Lucas Stach, Philipp Zabel, Michail Georgios Etairidis,
Wei Jinhua, Phil Reid, linux-kernel
From: Esben Haabendal <eha@deif.com>
Always update the stopped state when busy status have been checked.
This is identical to what was done before, with the exception of error
handling.
Without this change, some errors cause the stopped state to be left in
incorrect state in i2c_imx_stop(), i2c_imx_dma_read(), i2c_imx_read() and
i2c_imx_xfer().
Signed-off-by: Esben Haabendal <eha@deif.com>
---
drivers/i2c/busses/i2c-imx.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 742b548437af..f9c99b123188 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -430,10 +430,14 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
return -EAGAIN;
}
- if (for_busy && (temp & I2SR_IBB))
+ if (for_busy && (temp & I2SR_IBB)) {
+ i2c_imx->stopped = 0;
break;
- if (!for_busy && !(temp & I2SR_IBB))
+ }
+ if (!for_busy && !(temp & I2SR_IBB)) {
+ i2c_imx->stopped = 1;
break;
+ }
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&i2c_imx->adapter.dev,
"<%s> I2C bus is busy\n", __func__);
@@ -547,7 +551,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
result = i2c_imx_bus_busy(i2c_imx, 1);
if (result)
return result;
- i2c_imx->stopped = 0;
temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
temp &= ~I2CR_DMAEN;
@@ -578,7 +581,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
if (!i2c_imx->stopped) {
i2c_imx_bus_busy(i2c_imx, 0);
- i2c_imx->stopped = 1;
}
/* Disable I2C controller */
@@ -733,7 +735,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
i2c_imx_bus_busy(i2c_imx, 0);
- i2c_imx->stopped = 1;
} else {
/*
* For i2c master receiver repeat restart operation like:
@@ -861,7 +862,6 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
i2c_imx_bus_busy(i2c_imx, 0);
- i2c_imx->stopped = 1;
} else {
/*
* For i2c master receiver repeat restart operation like:
--
2.17.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/4] arm: dts: ls1021a: Enable I2C DMA support
[not found] <20180523095623.3347-1-esben.haabendal@gmail.com>
` (2 preceding siblings ...)
2018-05-23 9:56 ` [PATCH 3/4] i2c: imx: Simplify stopped state tracking Esben Haabendal
@ 2018-05-23 9:56 ` Esben Haabendal
3 siblings, 0 replies; 8+ messages in thread
From: Esben Haabendal @ 2018-05-23 9:56 UTC (permalink / raw)
To: linux-i2c
Cc: Esben Haabendal, Rob Herring, Mark Rutland, devicetree, linux-kernel
From: Esben Haabendal <eha@deif.com>
Gives substantial performance improvement for transfers larger than 16
bytes (DMA_THRESHOLD). Smaller transfers are unaffected.
Signed-off-by: Esben Haabendal <eha@deif.com>
---
arch/arm/boot/dts/ls1021a.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index c55d479971cc..1e5640701c65 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -363,6 +363,8 @@
interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "i2c";
clocks = <&clockgen 4 1>;
+ dma-names = "tx", "rx";
+ dmas = <&edma0 1 39>, <&edma0 1 38>;
status = "disabled";
};
@@ -374,6 +376,8 @@
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "i2c";
clocks = <&clockgen 4 1>;
+ dma-names = "tx", "rx";
+ dmas = <&edma0 1 37>, <&edma0 1 36>;
status = "disabled";
};
@@ -385,6 +389,8 @@
interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "i2c";
clocks = <&clockgen 4 1>;
+ dma-names = "tx", "rx";
+ dmas = <&edma0 1 35>, <&edma0 1 34>;
status = "disabled";
};
--
2.17.0
^ permalink raw reply related [flat|nested] 8+ messages in thread