[PATCH v9 07/12] iommu/arm-smmu-v3: Add CMDQ_PROD_STOP_FLAG to gate CMDQ submissions

Jason Gunthorpe jgg at nvidia.com
Tue Aug 25 09:36:11 PDT 2026


> [ ... 52 lines skipped ... ]
>  		while (!queue_has_space(&llq, n + sync)) {
>  			local_irq_restore(flags);
> +
> +			/* Avoid waiting for space if the SMMU is suspending */
> +			if (Q_STOP(READ_ONCE(cmdq->q.llq.prod)))
> +				return 0;
> +
>  			if (arm_smmu_cmdq_poll_until_not_full(smmu, cmdq, &llq))
>  				dev_err_ratelimited(smmu->dev, "CMDQ timeout\n");
>  			local_irq_save(flags);

 [Severity: Critical]
 Can this loop bypass the Q_STOP check if a suspend happens concurrently?

 If a thread enters the while loop because there's no space, and a concurrent
 task sets the CMDQ_PROD_STOP_FLAG while space becomes available:

 1. arm_smmu_cmdq_poll_until_not_full() updates llq.val with the latest global
    state, which now includes the newly set STOP_FLAG in llq.prod.
 2. The loop condition !queue_has_space(&llq, n + sync) now evaluates to false,
    causing the thread to exit the inner loop.
 3. This bypasses the Q_STOP(READ_ONCE(cmdq->q.llq.prod)) check inside the
    loop, as well as the Q_STOP(llq.prod) check at the top of the do-while loop.

 The thread would then successfully cmpxchg the new producer index with the
 STOP_FLAG set.

Make sense to me, having arm_smmu_cmdq_poll_until_not_full() reload
the llq and then not loop again from the top skips the Q_STOP
flag.

-- 
Jason



More information about the linux-arm-kernel mailing list