From: Nicolin Chen <nicolinc@nvidia.com>
To: "Peng Fan (OSS)" <peng.fan@oss.nxp.com>,
Robin Murphy <robin.murphy@arm.com>
Cc: Will Deacon <will@kernel.org>,
"Joerg Roedel (AMD)" <joro@8bytes.org>,
Jean-Philippe Brucker <jpb@kernel.org>,
Jason Gunthorpe <jgg@ziepe.ca>,
Thierry Reding <thierry.reding@kernel.org>,
Krishna Reddy <vdumpa@nvidia.com>,
Jonathan Hunter <jonathanh@nvidia.com>,
<linux-arm-kernel@lists.infradead.org>, <iommu@lists.linux.dev>,
<linux-kernel@vger.kernel.org>, <linux-tegra@vger.kernel.org>,
Peng Fan <peng.fan@nxp.com>
Subject: Re: [PATCH RFC v8 4/9] iommu/arm-smmu-v3: Use a per-domain CD table for non-PASID streams
Date: Fri, 13 Nov 2026 11:01:04 -0800 [thread overview]
Message-ID: <avdecPsIeaABLGkN@nvidia.com> (raw)
In-Reply-To: <20261113-b4-smmu-shared-sid-ver8-v8-4-587307a77f3a@nxp.com>
On Fri, Nov 13, 2026 at 09:27:16PM +0800, Peng Fan (OSS) wrote:
> +static int arm_smmu_alloc_cd_ptr_l2(struct arm_smmu_master *master, u32 ssid)
> +{
> + struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
> + unsigned int idx = arm_smmu_cdtab_l1_idx(ssid);
> + struct arm_smmu_cdtab_l2 **l2ptr = &cd_table->l2.l2ptrs[idx];
> + dma_addr_t l2ptr_dma;
> +
> + if (*l2ptr)
> + return 0;
> +
> + *l2ptr = dma_alloc_coherent(master->smmu->dev, sizeof(**l2ptr),
> + &l2ptr_dma, GFP_KERNEL);
> + if (!*l2ptr)
> + return -ENOMEM;
> +
> + arm_smmu_write_cd_l1_desc(&cd_table->l2.l1tab[idx], l2ptr_dma);
> + /* An invalid L1CD can be cached */
> + arm_smmu_sync_cd(master, ssid, false);
> + return 0;
> +}
This patch is a bit too big. Move this into a prep patch please.
> @@ -1793,9 +1801,22 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_device *smmu,
>
> static int arm_smmu_master_alloc_cd_tables(struct arm_smmu_master *master)
> {
> - return arm_smmu_alloc_cd_tables(master->smmu, &master->cd_table,
> - master->ssid_bits,
> - master->ats_always_on);
> + int ret;
> +
> + ret = arm_smmu_alloc_cd_tables(master->smmu, &master->cd_table,
> + master->ssid_bits,
> + master->ats_always_on);
> + if (ret)
> + return ret;
> +
> + if (master->cd_table.s1fmt == STRTAB_STE_0_S1FMT_64K_L2) {
> + ret = arm_smmu_alloc_cd_ptr_l2(master, IOMMU_NO_PASID);
> + if (ret) {
> + arm_smmu_free_cd_tables(master->smmu, &master->cd_table);
> + memset(&master->cd_table, 0, sizeof(master->cd_table));
> + }
It'd be helpful to have a line of inline comments stating why this
is needed here.
> @@ -1830,6 +1851,12 @@ static void arm_smmu_free_cd_tables(struct arm_smmu_device *smmu,
> }
> }
>
> +static int arm_smmu_domain_alloc_cd_tables(struct arm_smmu_domain *smmu_domain)
> +{
> + return arm_smmu_alloc_cd_tables(smmu_domain->smmu,
Hmm, that's not good. We are trying to decouple smmu_domain from an
SMMU instance so that one smmu_domain can be shared across multiple
SMMU instances.
Tying one instance to a domain is apparently going against it..
Instead, we would need an {smmu, cd_table, refcount} list. And it'd
make thing more complicated than letting master own CD table as-is.
Not sure if it's still worth doing so. Robin?
> @@ -3971,15 +4058,23 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
> if (smmu_domain->smmu != master->smmu)
> return -EINVAL;
>
> - if (!master->cd_table.in_ste &&
> + if (!((sid_domain->type & __IOMMU_DOMAIN_PAGING) &&
> + to_smmu_domain(sid_domain)->stage == ARM_SMMU_DOMAIN_S1) &&
> sid_domain->type != IOMMU_DOMAIN_IDENTITY &&
> sid_domain->type != IOMMU_DOMAIN_BLOCKED)
> return -EINVAL;
>
> + first = !arm_smmu_ssids_in_use(&master->cd_table);
> cdptr = arm_smmu_alloc_cd_ptr(master, pasid);
> if (!cdptr)
> return -ENOMEM;
>
> + if (first) {
> + cd0ptr = arm_smmu_master_get_cd_ptr(master, IOMMU_NO_PASID);
> + if (WARN_ON(!cd0ptr))
> + return -ENXIO;
You don't need "first" at all, given ...
> mutex_lock(&arm_smmu_asid_lock);
> ret = arm_smmu_attach_prepare(&state, &smmu_domain->domain);
> if (ret) {
> @@ -3995,7 +4090,30 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
> cd->data[0] |= cpu_to_le64(
> FIELD_PREP(CTXDESC_CD_0_ASID, smmu_domain->cd.asid));
>
> + /*
> + * The private CD table is taking over the STE now. Make sure its
> + * default substream matches the RID domain before the STE points at
> + * it, since non-PASID traffic follows CD[0].
> + */
> + if (first) {
> + if ((sid_domain->type & __IOMMU_DOMAIN_PAGING) &&
> + to_smmu_domain(sid_domain)->stage == ARM_SMMU_DOMAIN_S1) {
> + struct arm_smmu_cd cd0;
> +
> + arm_smmu_make_s1_cd(&cd0, master,
> + to_smmu_domain(sid_domain));
> + arm_smmu_write_cd_entry(master, IOMMU_NO_PASID,
> + cd0ptr, &cd0);
... there is only one place using the cd0ptr.
> @@ -4015,35 +4133,61 @@ static int arm_smmu_blocking_set_dev_pasid(struct iommu_domain *new_domain,
[...]
> /*
> - * When the last user of the CD table goes away downgrade the STE back
> - * to a non-cd_table one, by re-attaching its sid_domain.
> + * When the last user of the CD table goes away, switch the STE back to
> + * the RID domain's CD table (S1) or to the native bypass/abort STE
> + * (identity/blocked). Do not call attach_dev() for an S1 paging domain:
> + * this is a teardown path where allocation failures cannot be
> + * propagated. The private CD table is kept allocated for reuse and
> + * freed when the device goes away.
> */
> if (!arm_smmu_ssids_in_use(&master->cd_table)) {
> struct iommu_domain *sid_domain =
> iommu_driver_get_domain_for_dev(master->dev);
> - bool ats_always_on = master->ats_always_on &&
> - sid_domain->type != IOMMU_DOMAIN_BLOCKED;
> - bool downgrade = sid_domain->type == IOMMU_DOMAIN_IDENTITY ||
> - sid_domain->type == IOMMU_DOMAIN_BLOCKED;
>
> - if (!ats_always_on && downgrade)
> - sid_domain->ops->attach_dev(sid_domain, dev,
> - sid_domain);
> + if (!master->ats_always_on ||
> + sid_domain->type == IOMMU_DOMAIN_BLOCKED) {
> + if ((sid_domain->type & __IOMMU_DOMAIN_PAGING) &&
> + to_smmu_domain(sid_domain)->stage ==
> + ARM_SMMU_DOMAIN_S1) {
> + struct arm_smmu_ste ste;
> + struct arm_smmu_domain *sid_smmu_domain =
> + to_smmu_domain(sid_domain);
> +
> + mutex_lock(&arm_smmu_asid_lock);
> + arm_smmu_make_cdtable_ste(
> + &ste, master, &sid_smmu_domain->cd_table,
> + master->ats_enabled,
> + STRTAB_STE_1_S1DSS_SSID0);
> + arm_smmu_install_ste_for_dev(master, &ste);
> + mutex_unlock(&arm_smmu_asid_lock);
> + } else if (sid_domain->type == IOMMU_DOMAIN_IDENTITY ||
> + sid_domain->type == IOMMU_DOMAIN_BLOCKED) {
> + ret = sid_domain->ops->attach_dev(sid_domain, dev,
> + sid_domain);
I commented in v7 that attach_dev shouldn't propagate the ret..
Although your patch-9 clean it back to the right form, I think
there should be a way to prepare things cleanly so that you can
make a change here in one shot.
Nicolin
next prev parent reply other threads:[~2026-11-13 20:23 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 13:27 [PATCH RFC v8 0/9] iommu/arm-smmu-v3: Support shared Stream IDs Peng Fan (OSS)
2026-11-13 13:27 ` [PATCH RFC v8 1/9] iommu/arm-smmu-v3: Allocate streams individually Peng Fan (OSS)
2026-11-13 13:27 ` [PATCH RFC v8 2/9] iommu/arm-smmu-v3: Delay stream allocation to inside the mutex Peng Fan (OSS)
2026-11-13 13:27 ` [PATCH RFC v8 3/9] iommu/arm-smmu-v3: Plumb the CD table into the CD helpers Peng Fan (OSS)
2026-11-13 13:27 ` [PATCH RFC v8 4/9] iommu/arm-smmu-v3: Use a per-domain CD table for non-PASID streams Peng Fan (OSS)
2026-11-13 19:01 ` Nicolin Chen [this message]
2026-11-13 13:27 ` [PATCH RFC v8 5/9] iommu/arm-smmu-v3: Support shared SIDs in insert/remove_master Peng Fan (OSS)
2026-11-13 13:27 ` [PATCH RFC v8 6/9] iommu/arm-smmu-v3: Group aliasing devices into the same IOMMU group Peng Fan (OSS)
2026-11-13 13:27 ` [PATCH RFC v8 7/9] iommu/arm-smmu-v3: Wire up shared-SID STE ordering and feature gating Peng Fan (OSS)
2026-11-13 19:09 ` Nicolin Chen
2026-11-13 13:27 ` [PATCH RFC v8 8/9] iommu/arm-smmu-v3: Serialize shared-SID changes with attach Peng Fan (OSS)
2026-11-13 13:27 ` [PATCH RFC v8 9/9] iommu/arm-smmu-v3: Quiesce PASID before mm release unlinks Peng Fan (OSS)
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=avdecPsIeaABLGkN@nvidia.com \
--to=nicolinc@nvidia.com \
--cc=iommu@lists.linux.dev \
--cc=jgg@ziepe.ca \
--cc=jonathanh@nvidia.com \
--cc=joro@8bytes.org \
--cc=jpb@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=peng.fan@nxp.com \
--cc=peng.fan@oss.nxp.com \
--cc=robin.murphy@arm.com \
--cc=thierry.reding@kernel.org \
--cc=vdumpa@nvidia.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.