i2c: designware: Synchronize IRQs when unregistering slave client
diff mbox series

Message ID 20190815135211.25452-1-jarkko.nikula@linux.intel.com
State Accepted
Headers show
Series
  • i2c: designware: Synchronize IRQs when unregistering slave client
Related show

Commit Message

Jarkko Nikula Aug. 15, 2019, 1:52 p.m. UTC
Make sure interrupt handler i2c_dw_irq_handler_slave() has finished
before clearing the the dev->slave pointer in i2c_dw_unreg_slave().

There is possibility for a race if i2c_dw_irq_handler_slave() is running
on another CPU while clearing the dev->slave pointer.

Reported-by: Krzysztof Adamski <krzysztof.adamski@nokia.com>
Reported-by: Wolfram Sang <wsa@the-dreams.de>
Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
I tried testing simultaneous slave registration/unregistration while
accessing that slave from another I2C master with scripts below but
didn't see issue without or with this patch. But my testing time was
rather short and the race can be hard to hit while possible.

cd /sys/bus/i2c/devices/i2c-[slave port number]/;
while :; do echo slave-24c02 0x1065 >new_device; sleep 1; echo 0x1065 >delete_device; sleep 0.1; done
while :; do i2cdump -y [master port that is connected to slave] 0x65; done
---
 drivers/i2c/busses/i2c-designware-slave.c | 1 +
 1 file changed, 1 insertion(+)

Comments

Wolfram Sang Aug. 29, 2019, 6:48 p.m. UTC | #1
On Thu, Aug 15, 2019 at 04:52:11PM +0300, Jarkko Nikula wrote:
> Make sure interrupt handler i2c_dw_irq_handler_slave() has finished
> before clearing the the dev->slave pointer in i2c_dw_unreg_slave().
> 
> There is possibility for a race if i2c_dw_irq_handler_slave() is running
> on another CPU while clearing the dev->slave pointer.
> 
> Reported-by: Krzysztof Adamski <krzysztof.adamski@nokia.com>
> Reported-by: Wolfram Sang <wsa@the-dreams.de>
> Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>

Applied to for-current, thanks!

Patch
diff mbox series

diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
index e7f9305b2dd9..f5f001738df5 100644
--- a/drivers/i2c/busses/i2c-designware-slave.c
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -94,6 +94,7 @@  static int i2c_dw_unreg_slave(struct i2c_client *slave)
 
 	dev->disable_int(dev);
 	dev->disable(dev);
+	synchronize_irq(dev->irq);
 	dev->slave = NULL;
 	pm_runtime_put(dev->dev);