summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMyeonghun Pak <mhun512@gmail.com>2026-10-17 23:35:16 -0400
committerAndi Shyti <andi.shyti@kernel.org>2026-10-24 00:05:15 +0200
commitf7b70efba26963bf725f10574cc071f86cd5ee1d (patch)
tree9a63cbea72e30773ebc8baba7b56db59595b88a2
parentf0e53c16b1562f06775e46ceb263b72785363674 (diff)
i2c: sh_mobile: request IRQs after mapping registers
The managed IRQ handlers are acquired before the managed register mapping, so devres unmaps the registers before freeing the IRQs. A transfer wakes its waiter before the ISR's final register read, and unregistering the adapter does not synchronize these IRQs. An in-flight handler can therefore still access the mapping when it is released during driver detach. With forced-threaded IRQs, the handler can be preempted after waking the transfer waiter and before its final ICSR read. Map the registers before requesting the IRQs so that managed cleanup frees and synchronizes all handlers before unmapping their registers. Keep IRQs available while unregistering the adapter because client removal may perform transfers. This issue was identified as part of our ongoing research while reviewing kernel code. Co-developed-by: Ijae Kim <ae878000@gmail.com> Signed-off-by: Ijae Kim <ae878000@gmail.com> Signed-off-by: Myeonghun Pak <mhun512@gmail.com> Signed-off-by: Andi Shyti <andi.shyti@kernel.org> Link: https://patch.msgid.link/20261017233416.47b09ffff48f.i2c-sh-mobile@gmail.com
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c8
1 files changed, 4 insertions, 4 deletions
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index dae8967f8749..3a55f803e4f1 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -880,10 +880,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
return PTR_ERR(pd->clk);
}
- ret = sh_mobile_i2c_hook_irqs(dev, pd);
- if (ret)
- return ret;
-
pd->dev = &dev->dev;
platform_set_drvdata(dev, pd);
@@ -891,6 +887,10 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
if (IS_ERR(pd->reg))
return PTR_ERR(pd->reg);
+ ret = sh_mobile_i2c_hook_irqs(dev, pd);
+ if (ret)
+ return ret;
+
ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed);
pd->bus_speed = (ret || !bus_speed) ? I2C_MAX_STANDARD_MODE_FREQ : bus_speed;
pd->clks_per_count = 1;