[PATCH] i3c: master: adi: initialize the lock before enabling interrupts
Frank Li
Frank.li at oss.nxp.com
Wed Jun 17 13:43:43 PDT 2026
On Wed, Jun 17, 2026 at 11:01:38PM +0800, Runyu Xiao wrote:
> 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 at vger.kernel.org
> Signed-off-by: Runyu Xiao <runyu.xiao at seu.edu.cn>
> ---
Reviewed-by: Frank Li <Frank.Li at nxp.com>
> drivers/i3c/master/adi-i3c-master.c | 15 +++++++--------
> 1 file changed, 7 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/i3c/master/adi-i3c-master.c b/drivers/i3c/master/adi-i3c-master.c
> index 82ac0b3d057a..cf873d46e10f 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);
> }
> --
> 2.34.1
>
More information about the linux-i3c
mailing list