i2c: emev2: avoid race when unregistering slave client

After we disabled interrupts, there might still be an active one
running. Sync before clearing the pointer to the slave device.

Fixes: c31d0a0002 ("i2c: emev2: add slave support")
Reported-by: Krzysztof Adamski <krzysztof.adamski@nokia.com>
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: Krzysztof Adamski <krzysztof.adamski@nokia.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
Wolfram Sang 2019-08-08 21:54:17 +02:00 committed by Wolfram Sang
parent 7b814d852a
commit d7437fc0d8
1 changed files with 12 additions and 4 deletions

View File

@ -69,6 +69,7 @@ struct em_i2c_device {
struct completion msg_done;
struct clk *sclk;
struct i2c_client *slave;
int irq;
};
static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg)
@ -339,6 +340,12 @@ static int em_i2c_unreg_slave(struct i2c_client *slave)
writeb(0, priv->base + I2C_OFS_SVA0);
/*
* Wait for interrupt to finish. New slave irqs cannot happen because we
* cleared the slave address and, thus, only extension codes will be
* detected which do not use the slave ptr.
*/
synchronize_irq(priv->irq);
priv->slave = NULL;
return 0;
@ -355,7 +362,7 @@ static int em_i2c_probe(struct platform_device *pdev)
{
struct em_i2c_device *priv;
struct resource *r;
int irq, ret;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@ -390,8 +397,8 @@ static int em_i2c_probe(struct platform_device *pdev)
em_i2c_reset(&priv->adap);
irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(&pdev->dev, irq, em_i2c_irq_handler, 0,
priv->irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(&pdev->dev, priv->irq, em_i2c_irq_handler, 0,
"em_i2c", priv);
if (ret)
goto err_clk;
@ -401,7 +408,8 @@ static int em_i2c_probe(struct platform_device *pdev)
if (ret)
goto err_clk;
dev_info(&pdev->dev, "Added i2c controller %d, irq %d\n", priv->adap.nr, irq);
dev_info(&pdev->dev, "Added i2c controller %d, irq %d\n", priv->adap.nr,
priv->irq);
return 0;