mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
i3c: master: adi: free the IRQ before unregistering the master
adi_i3c_master_irq() is requested with devm_request_irq(), so it stays
registered when adi_i3c_master_remove() runs, and the writes masking the
controller IRQ sources do not synchronize with a handler that is already
running on another CPU. i3c_master_unregister() then frees the
struct i3c_dev_desc objects that master->ibi.slots[] still point to, so
the IBI path in adi_i3c_master_handle_ibi() can dereference freed memory.
Fix this by storing the IRQ number in the private structure and calling
devm_free_irq() after the IRQ sources are masked, so a running handler
is finished before the master is torn down.
This issue was found by an in-house static analysis tool.
Fixes: a79ac2cdc9 ("i3c: master: Add driver for Analog Devices I3C Controller IP")
Cc: stable@vger.kernel.org
Co-developed-by: Song Li <songl@zju.edu.cn>
Signed-off-by: Song Li <songl@zju.edu.cn>
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260923085340.490776-1-fanwu01@zju.edu.cn
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
parent
bf9ec06c90
commit
1c1e2d90aa
|
|
@ -115,6 +115,7 @@ struct adi_i3c_master {
|
|||
spinlock_t lock; /* Protect transfer */
|
||||
} xferqueue;
|
||||
void __iomem *regs;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
unsigned long i3c_scl_lim;
|
||||
struct {
|
||||
|
|
@ -957,6 +958,7 @@ static int adi_i3c_master_probe(struct platform_device *pdev)
|
|||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
master->irq = irq;
|
||||
|
||||
version = readl(master->regs + ADI_AXI_REG_VERSION);
|
||||
if (ADI_AXI_PCORE_VER_MAJOR(version) != 1)
|
||||
|
|
@ -1001,6 +1003,8 @@ static void adi_i3c_master_remove(struct platform_device *pdev)
|
|||
writel(0x00, master->regs + REG_IRQ_MASK);
|
||||
writel(0x01, master->regs + REG_ENABLE);
|
||||
|
||||
devm_free_irq(&pdev->dev, master->irq, master);
|
||||
|
||||
i3c_master_unregister(&master->base);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user