Message ID | 20190808193910.12365-1-wsa+renesas@sang-engineering.com (mailing list archive) |
---|---|
State | Accepted |
Delegated to: | Geert Uytterhoeven |
Headers | show |
Series | i2c: rcar: avoid race when unregistering slave client | expand |
On Thu, Aug 08, 2019 at 09:39:10PM +0200, Wolfram Sang wrote: >After we disabled interrupts, there might still be an active one >running. Sync before clearing the pointer to the slave device. > >Reported-by: Krzysztof Adamski <krzysztof.adamski@nokia.com> >Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> >--- > >Tested with a Lager board (Renesas R-Car H2) and no regressions found. I >tried to run into this race via stress-testing but failed. The race >window is tiny, but it is still there, so let's fix it. > > drivers/i2c/busses/i2c-rcar.c | 11 +++++++---- > 1 file changed, 7 insertions(+), 4 deletions(-) > Reviewed-by: Krzysztof Adamski <krzysztof.adamski@nokia.com>
On Thu, Aug 08, 2019 at 09:39:10PM +0200, Wolfram Sang wrote: > After we disabled interrupts, there might still be an active one > running. Sync before clearing the pointer to the slave device. > > Reported-by: Krzysztof Adamski <krzysztof.adamski@nokia.com> > Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Applied to for-current, thanks!
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index d39a4606f72d..531c01100b56 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -139,6 +139,7 @@ struct rcar_i2c_priv { enum dma_data_direction dma_direction; struct reset_control *rstc; + int irq; }; #define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) @@ -861,9 +862,11 @@ static int rcar_unreg_slave(struct i2c_client *slave) WARN_ON(!priv->slave); + /* disable irqs and ensure none is running before clearing ptr */ rcar_i2c_write(priv, ICSIER, 0); rcar_i2c_write(priv, ICSCR, 0); + synchronize_irq(priv->irq); priv->slave = NULL; pm_runtime_put(rcar_i2c_priv_to_dev(priv)); @@ -918,7 +921,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) struct i2c_adapter *adap; struct device *dev = &pdev->dev; struct i2c_timings i2c_t; - int irq, ret; + int ret; /* Otherwise logic will break because some bytes must always use PIO */ BUILD_BUG_ON_MSG(RCAR_MIN_DMA_LEN < 3, "Invalid min DMA length"); @@ -984,10 +987,10 @@ static int rcar_i2c_probe(struct platform_device *pdev) pm_runtime_put(dev); - irq = platform_get_irq(pdev, 0); - ret = devm_request_irq(dev, irq, rcar_i2c_irq, 0, dev_name(dev), priv); + priv->irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, dev_name(dev), priv); if (ret < 0) { - dev_err(dev, "cannot get irq %d\n", irq); + dev_err(dev, "cannot get irq %d\n", priv->irq); goto out_pm_disable; }
After we disabled interrupts, there might still be an active one running. Sync before clearing the pointer to the slave device. Reported-by: Krzysztof Adamski <krzysztof.adamski@nokia.com> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> --- Tested with a Lager board (Renesas R-Car H2) and no regressions found. I tried to run into this race via stress-testing but failed. The race window is tiny, but it is still there, so let's fix it. drivers/i2c/busses/i2c-rcar.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)