summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRunyu Xiao <runyu.xiao@seu.edu.cn>2026-06-17 23:01:38 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-07 17:22:57 +0200
commita15a1b95de980362c14f32f519b293b0d12ce86f (patch)
tree40dc43a7f1e916e66b9d35b73894cbefde8a40a7
parent1894fc7a3bab90143dcd26ef8ee27040ef4a7501 (diff)
downloadlinux-a15a1b95de980362c14f32f519b293b0d12ce86f.tar.gz
linux-a15a1b95de980362c14f32f519b293b0d12ce86f.zip
i3c: master: adi: initialize the lock before enabling interrupts
commit 8a53f9102a0d3eeb8784999f925028acf339c276 upstream. adi_i3c_master_probe() requests the IRQ and unmasks REG_IRQ_PENDING_CMDR before the controller's IBI state, transfer queue list and transfer queue lock are initialized. A pending CMDR interrupt can therefore run adi_i3c_master_irq() and take master->xferqueue.lock before the dynamic lock has been initialized. This issue was found by our static analysis tool and then manually reviewed against the current tree. The grounded PoC kept the probe ordering and the IRQ path adi_i3c_master_probe() -> adi_i3c_master_irq() -> xferqueue.lock, with a pending CMDR interrupt arriving after REG_IRQ_PENDING_CMDR is unmasked. Lockdep reported: INFO: trying to register non-static key. you didn't initialize this object before use? lock_acquire+0xbb/0x290 _raw_spin_lock_irqsave+0x36/0x60 adi_i3c_master_irq+0x32/0x56 [vuln_msv] adi_i3c_master_probe+0x5a/0xf47 [vuln_msv] Initialize the transfer queue and IBI state before requesting and unmasking the IRQ. Fixes: a79ac2cdc91d ("i3c: master: Add driver for Analog Devices I3C Controller IP") Cc: stable@vger.kernel.org Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20260617150138.628578-1-runyu.xiao@seu.edu.cn Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/i3c/master/adi-i3c-master.c15
1 files changed, 7 insertions, 8 deletions
diff --git a/drivers/i3c/master/adi-i3c-master.c b/drivers/i3c/master/adi-i3c-master.c
index d329faf4b3f9..f0c2ddb2f4b2 100644
--- a/drivers/i3c/master/adi-i3c-master.c
+++ b/drivers/i3c/master/adi-i3c-master.c
@@ -967,17 +967,9 @@ static int adi_i3c_master_probe(struct platform_device *pdev)
writel(0x00, master->regs + REG_ENABLE);
writel(0x00, master->regs + REG_IRQ_MASK);
- ret = devm_request_irq(&pdev->dev, irq, adi_i3c_master_irq, 0,
- dev_name(&pdev->dev), master);
- if (ret)
- return ret;
-
platform_set_drvdata(pdev, master);
master->free_rr_slots = GENMASK(ADI_MAX_DEVS, 1);
-
- writel(REG_IRQ_PENDING_CMDR, master->regs + REG_IRQ_MASK);
-
spin_lock_init(&master->ibi.lock);
master->ibi.num_slots = 15;
master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots,
@@ -989,6 +981,13 @@ static int adi_i3c_master_probe(struct platform_device *pdev)
spin_lock_init(&master->xferqueue.lock);
INIT_LIST_HEAD(&master->xferqueue.list);
+ ret = devm_request_irq(&pdev->dev, irq, adi_i3c_master_irq, 0,
+ dev_name(&pdev->dev), master);
+ if (ret)
+ return ret;
+
+ writel(REG_IRQ_PENDING_CMDR, master->regs + REG_IRQ_MASK);
+
return i3c_master_register(&master->base, &pdev->dev,
&adi_i3c_master_ops, false);
}