public inbox for iommu@lists.linux-foundation.org
 help / color / mirror / Atom feed
From: Pranjal Shrivastava <praan@google.com>
To: Daniel Mentz <danielmentz@google.com>
Cc: iommu@lists.linux.dev, Will Deacon <will@kernel.org>,
	Joerg Roedel <joro@8bytes.org>,
	Robin Murphy <robin.murphy@arm.com>,
	Jason Gunthorpe <jgg@ziepe.ca>,
	Mostafa Saleh <smostafa@google.com>,
	Nicolin Chen <nicolinc@nvidia.com>,
	Ashish Mhetre <amhetre@nvidia.com>,
	Sairaj Kodilkar <sarunkod@amd.com>
Subject: Re: [PATCH v5 07/10] iommu/arm-smmu-v3: Implement pm_runtime & system sleep ops
Date: Tue, 10 Mar 2026 21:40:35 +0000	[thread overview]
Message-ID: <abCP0wLkVvUSUeYI@google.com> (raw)
In-Reply-To: <CAE2F3rAqyX_CQaN2Wt2=uTYJqYUV3nbrfmog0YyvPr4pgYU5xQ@mail.gmail.com>

On Tue, Mar 10, 2026 at 02:16:31PM -0700, Daniel Mentz wrote:
> On Tue, Mar 10, 2026 at 9:58 AM Pranjal Shrivastava <praan@google.com> wrote:
> >
> > On Mon, Mar 09, 2026 at 06:45:09PM -0700, Daniel Mentz wrote:
> > > On Mon, Jan 26, 2026 at 7:12 AM Pranjal Shrivastava <praan@google.com> wrote:
> > > >
> > > > +static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
> > > > +{
> > > > +       struct arm_smmu_device *smmu = dev_get_drvdata(dev);
> > > > +       int timeout = ARM_SMMU_SUSPEND_TIMEOUT_US;
> > > > +       u32 enables;
> > > > +       int ret;
> > > > +
> > > > +       /* Try to suspend the device, wait for in-flight submissions */
> > > > +       do {
> > > > +               if (atomic_cmpxchg(&smmu->nr_cmdq_users, 1, 0) == 1)
> > >
> > >
> > > I understand we must follow the rule: do not elide any invalidations
> > > while SMMU is still enabled. Otherwise, the following sequence of
> > > events might occur:
> > >  * The driver clears a table descriptor
> > >  * The TLBI command is skipped
> > >  * The driver frees the page that backed the translation table
> > >  * The page is re-allocated for some unrelated purpose
> > >  * SMMU performs a table walk and then descends into the page that has
> > > been reallocated, misinterpreting its contents.
> > >
> > > Can you disable SMMU before setting nr_cmdq_users to 0?
> > >
> >
> > No, that'd be racy, if I disable the smmu but nr_cmdq_users != 0 an
> > "owner" thread might believe that the SMMU is still functional and poll
> > for consumption.
> 
> I assume that SMMU still processes commands if SMMU_CR0.SMMUEN is
> cleared but SMMU_CR0.CMDQEN is set. The arch spec reads: "When
> translation is not enabled for a Security state, an SMMU: [...] Can
> process commands after the relevant queue pointers are initialized and
> SMMU_(*_)CR0.CMDQEN is enabled." Also, the sequence described under
> "Arm recommends that software initializing the SMMU performs the
> following steps:" suggests this behavior. The existing driver code
> also relies on this when it runs CMDQ_OP_CFGI_ALL before setting
> SMMU_CR0.SMMUEN.
> 
> >
> > I don't think that the SMMU would perform a walk as we first set the
> > nr_cmdq_users == 0 to stop command submissions and then immediately set
> > GBPA to abort. IF a command submission raced with this, we wait for the
> 
> To ensure we're on the same page: Setting SMMU_GBPA.ABORT doesn't do
> anything while SMMU_CR0.SMMUEN is set. SMMU_GBPA only plays a role if
> SMMU_CR0.SMMUEN is cleared.
> 

I think you're missing that we *DO* actually set SMMUEN = 0 *with* the
GBPA abort, please look at this part of the patch:

+	/* Abort all transactions before disable to avoid spurious bypass */
+	arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
+
+	/* Disable the SMMU via CR0.EN and all queues except CMDQ */
+	enables = CR0_CMDQEN;
+	ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0, ARM_SMMU_CR0ACK);
+	if (ret) {
+		dev_err(smmu->dev, "Timed-out while disabling smmu\n");
+		atomic_set(&smmu->nr_cmdq_users, 1);
+		return ret;
+	}

We disable everything except for the CMDQ. Since, everything is disabled
at this point, any new commands can safely be elided as the SMMU won't
access any config structures as mentioned by the spec.

> The moment you set nr_cmdq_users == 0, you potentially start eliding
> TBLIs which means that the TLB entries are at risk of becoming stale.

Not really, the SMMU isn't accessing anything since SMMUEN=0 and GBPA is
set by this point.

> How about the following sequenc of events:
> 
> * suspend handler sets nr_cmdq_users == 0
> * arm_smmu_cmdq_issue_cmdlist() stops updating the producer index
> which means that TLBIs are not executed
> * (sequence described above)
> 
> Now that I think more about it: I'm concerned that if we set
> nr_cmdq_users == 0, the hw prod index will no longer be updated and
> the arm_smmu_drain_queues() function will wait for ever, because the
> cons index is not catching up.
> 

If we go ahead with the suggestion to completely elide a command
submission, if (nr_users_cmdq == 0) return 0; (as discussed in the other
thread), then we don't update llq.cons / prod. Then this shouldn't be an
issue right?

The problem I see in swapping the sequence is::

+	/* Abort all transactions before disable to avoid spurious bypass */
+	arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
+
+	/* Disable the SMMU via CR0.EN and all queues except CMDQ */
+	enables = CR0_CMDQEN; <-- Tear down everything except CMDQ
+	ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0, ARM_SMMU_CR0ACK);
+	if (ret) {
+		dev_err(smmu->dev, "Timed-out while disabling smmu\n");
+		atomic_set(&smmu->nr_cmdq_users, 1);
+		return ret;
+	}
+	/* Try to suspend the device, wait for in-flight submissions */
+	do {
+		if (atomic_cmpxchg(&smmu->nr_cmdq_users, 1, 0) == 1)
+			break;
+
+		udelay(1);
+	} while (--timeout);
+
+	if (!timeout) {
+		dev_warn(smmu->dev, "SMMU in use, aborting suspend\n"); 
+		return -EAGAIN; <--- suspend failed, but we already tore down the smmu
+	}
+
+
+	/*
+	 * At this point the SMMU is completely disabled and won't access
+	 * any translation/config structures, even speculative accesses
+	 * aren't performed as per the IHI0070 spec (section 6.3.9.6).
+	 */
+
+	/* Wait for the CMDQs to be drained to flush any pending commands */
+	ret = arm_smmu_drain_queues(smmu);
+	if (ret)
+		dev_err(smmu->dev, "Draining queues timed-out..forcing suspend\n");
+
+	/* Disable everything */
+	arm_smmu_device_disable(smmu); <---- Note that this still just disables the CMDQ
+	dev_dbg(dev, "Suspended smmu\n");
+
+	return 0;
+}
+

In the current implementation we first see if we can suspend only then
tear down the SMMU (Except for the CMDQ),

I think this would NOT be a problem if we just bail out of issue_cmdlist
early as discussed on the other thread if (nr_cmdq_users == 0) return 0;
that way, we don't end up in a "fake command" consumption situation
which could lead to the cons never catching up while draining the queue.

Thanks
Praan

  reply	other threads:[~2026-03-10 21:40 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-26 15:11 [PATCH v5 00/10] iommu/arm-smmu-v3: Implement Runtime/System Sleep ops Pranjal Shrivastava
2026-01-26 15:11 ` [PATCH v5 01/10] iommu/arm-smmu-v3: Refactor arm_smmu_setup_irqs Pranjal Shrivastava
2026-01-26 15:11 ` [PATCH v5 02/10] iommu/arm-smmu-v3: Add a helper to drain cmd queues Pranjal Shrivastava
2026-01-26 15:11 ` [PATCH v5 03/10] iommu/tegra241-cmdqv: Add a helper to drain VCMDQs Pranjal Shrivastava
2026-01-26 15:11 ` [PATCH v5 04/10] iommu/tegra241-cmdqv: Restore PROD and CONS after resume Pranjal Shrivastava
2026-01-26 15:11 ` [PATCH v5 05/10] iommu/arm-smmu-v3: Cache and restore MSI config Pranjal Shrivastava
2026-01-26 15:11 ` [PATCH v5 06/10] iommu/arm-smmu-v3: Add a usage counter for cmdq Pranjal Shrivastava
2026-03-08 21:23   ` Daniel Mentz
2026-03-09 19:46     ` Pranjal Shrivastava
2026-03-09 21:13       ` Pranjal Shrivastava
2026-03-09 22:56         ` Daniel Mentz
2026-03-10 16:46           ` Pranjal Shrivastava
2026-03-09 22:41       ` Daniel Mentz
2026-03-10 16:54         ` Pranjal Shrivastava
2026-03-11  4:43           ` Daniel Mentz
2026-03-11 13:53             ` Pranjal Shrivastava
2026-03-11 22:56               ` Daniel Mentz
2026-03-16 15:36                 ` Pranjal Shrivastava
2026-01-26 15:11 ` [PATCH v5 07/10] iommu/arm-smmu-v3: Implement pm_runtime & system sleep ops Pranjal Shrivastava
2026-03-10  1:45   ` Daniel Mentz
2026-03-10 16:58     ` Pranjal Shrivastava
2026-03-10 21:16       ` Daniel Mentz
2026-03-10 21:40         ` Pranjal Shrivastava [this message]
2026-03-11  0:12           ` Daniel Mentz
2026-03-11  5:31             ` Pranjal Shrivastava
2026-03-11 17:26               ` Daniel Mentz
2026-03-16 15:05                 ` Pranjal Shrivastava
2026-03-12 19:20   ` Daniel Mentz
2026-01-26 15:11 ` [PATCH v5 08/10] iommu/arm-smmu-v3: Handle gerror during suspend Pranjal Shrivastava
2026-01-26 15:11 ` [PATCH v5 09/10] iommu/arm-smmu-v3: Enable pm_runtime and setup devlinks Pranjal Shrivastava
2026-01-26 15:11 ` [PATCH v5 10/10] iommu/arm-smmu-v3: Invoke pm_runtime before hw access Pranjal Shrivastava
2026-02-06 15:48 ` [PATCH v5 00/10] iommu/arm-smmu-v3: Implement Runtime/System Sleep ops Ashish Mhetre
2026-02-11 13:33   ` Pranjal Shrivastava

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=abCP0wLkVvUSUeYI@google.com \
    --to=praan@google.com \
    --cc=amhetre@nvidia.com \
    --cc=danielmentz@google.com \
    --cc=iommu@lists.linux.dev \
    --cc=jgg@ziepe.ca \
    --cc=joro@8bytes.org \
    --cc=nicolinc@nvidia.com \
    --cc=robin.murphy@arm.com \
    --cc=sarunkod@amd.com \
    --cc=smostafa@google.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox