Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1fe671b6 authored by Wolfram Sang's avatar Wolfram Sang Committed by Greg Kroah-Hartman
Browse files

i2c: emev2: avoid race when unregistering slave client



[ Upstream commit d7437fc0d8291181debe032671a289b6bd93f46f ]

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

Fixes: c31d0a00 ("i2c: emev2: add slave support")
Reported-by: default avatarKrzysztof Adamski <krzysztof.adamski@nokia.com>
Signed-off-by: default avatarWolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: default avatarKrzysztof Adamski <krzysztof.adamski@nokia.com>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent f5679e5a
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -72,6 +72,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)
@@ -342,6 +343,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;
@@ -358,7 +365,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)
@@ -391,8 +398,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;
@@ -402,7 +409,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;