[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