From: "Peng Fan (OSS)" <peng.fan@oss.nxp.com>
To: Will Deacon <will@kernel.org>,
Robin Murphy <robin.murphy@arm.com>,
"Joerg Roedel (AMD)" <joro@8bytes.org>,
Jean-Philippe Brucker <jpb@kernel.org>,
Jason Gunthorpe <jgg@ziepe.ca>
Cc: linux-arm-kernel@lists.infradead.org, iommu@lists.linux.dev,
linux-kernel@vger.kernel.org, Peng Fan <peng.fan@nxp.com>
Subject: [PATCH RFC 2/4] iommu/arm-smmu-v3: Support shared SIDs in insert/remove_master
Date: Wed, 16 Sep 2026 23:12:35 +0800 [thread overview]
Message-ID: <20260916-smmu-shared-sid-v1-2-517384504aee@nxp.com> (raw)
In-Reply-To: <20260916-smmu-shared-sid-v1-0-517384504aee@nxp.com>
From: Peng Fan <peng.fan@nxp.com>
When arm_smmu_insert_master() encounters a SID already owned by a
different master, instead of failing with -ENODEV, increment the
canonical stream's ref_count and mark both masters as shared_sid.
A per-SID shared_link list tracks all co-sharing streams so that
ownership can be transferred when the canonical owner is removed.
When arm_smmu_remove_master() removes a master:
- Owning master with ref_count > 1: transfer the XArray entry to
the next sharer via list_first_entry + xa_store, and clear
shared_sid on the successor when ref_count drops to 1.
- Owning master with ref_count == 1: xa_erase (sole owner).
- Non-owning sharer: list_del + ref_count--. Clear shared_sid on
the canonical owner when ref_count drops to 1.
New fields:
- arm_smmu_stream: ref_count, ste_installed, shared_link (list_head)
- arm_smmu_master: shared_sid (disables SVA, stall, IOPF)
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 88 +++++++++++++++++++++++------
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 23 ++++++++
2 files changed, 94 insertions(+), 17 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 65e448a69a019..f53e1871426a5 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4095,6 +4095,7 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
new_stream->id = fwspec->ids[i];
new_stream->master = master;
+ INIT_LIST_HEAD(&new_stream->shared_link);
}
/* Put the ids into order for sorted to_merge/to_unref arrays */
@@ -4118,31 +4119,46 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
existing = xa_load(&smmu->streams, sid);
if (existing) {
- dev_warn(master->dev,
- "Aliasing StreamID 0x%x (from %s) unsupported, expect DMA to be broken\n",
- sid, dev_name(existing->master->dev));
- ret = -ENODEV;
- break;
+ /*
+ * Another master already owns this SID. Bump the
+ * refcount, mark both masters as sharing, and link
+ * our stream so ownership can be transferred later.
+ */
+ existing->ref_count++;
+ existing->master->shared_sid = true;
+ master->shared_sid = true;
+ list_add_tail(&new_stream->shared_link,
+ &existing->shared_link);
+ } else {
+ new_stream->ref_count = 1;
+ new_stream->ste_installed = false;
+ ret = xa_err(xa_store(&smmu->streams, sid, new_stream,
+ GFP_KERNEL));
+ if (ret)
+ break;
}
-
- /*
- * xa_store() returns the old entry (void *) on success
- * or an ERR_PTR on allocation failure. Use xa_err() to
- * convert to a standard errno.
- */
- ret = xa_err(xa_store(&smmu->streams, sid, new_stream,
- GFP_KERNEL));
- if (ret)
- break;
}
if (ret) {
+ /* Undo any successful insertions / refcount bumps */
for (i--; i >= 0; i--) {
+ struct arm_smmu_stream *existing;
u32 sid = master->streams[i].id;
if (i > 0 && master->streams[i - 1].id == sid)
continue;
- xa_erase(&smmu->streams, sid);
+
+ existing = xa_load(&smmu->streams, sid);
+ if (!existing)
+ continue;
+ if (existing->master == master) {
+ xa_erase(&smmu->streams, sid);
+ } else {
+ list_del_init(&master->streams[i].shared_link);
+ existing->ref_count--;
+ if (existing->ref_count == 1)
+ existing->master->shared_sid = false;
+ }
}
kfree(master->streams);
kfree(master->build_invs);
@@ -4163,11 +4179,49 @@ static void arm_smmu_remove_master(struct arm_smmu_master *master)
mutex_lock(&smmu->streams_mutex);
for (i = 0; i < master->num_streams; i++) {
u32 sid = master->streams[i].id;
+ struct arm_smmu_stream *stream;
/* Skip intra-master duplicate SIDs */
if (i > 0 && master->streams[i - 1].id == sid)
continue;
- xa_erase(&smmu->streams, sid);
+
+ stream = xa_load(&smmu->streams, sid);
+ if (!stream)
+ continue;
+
+ if (stream->master == master) {
+ /*
+ * This master owns the canonical XArray entry.
+ * Erase when the last reference drops; otherwise
+ * transfer ownership to the next sharer.
+ */
+ stream->ref_count--;
+ if (stream->ref_count == 0) {
+ xa_erase(&smmu->streams, sid);
+ } else {
+ struct arm_smmu_stream *next;
+
+ next = list_first_entry(&stream->shared_link,
+ struct arm_smmu_stream,
+ shared_link);
+ list_del(&stream->shared_link);
+ next->ref_count = stream->ref_count;
+ next->ste_installed = stream->ste_installed;
+ xa_store(&smmu->streams, sid, next,
+ GFP_KERNEL);
+ if (next->ref_count == 1)
+ next->master->shared_sid = false;
+ }
+ } else {
+ /*
+ * Non-owning sharer: unlink from the shared list
+ * and drop the refcount on the canonical entry.
+ */
+ list_del_init(&master->streams[i].shared_link);
+ stream->ref_count--;
+ if (stream->ref_count == 1)
+ stream->master->shared_sid = false;
+ }
}
mutex_unlock(&smmu->streams_mutex);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 97dc97ac704d9..cf245b5de2bd2 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -976,6 +976,24 @@ struct arm_smmu_device {
struct arm_smmu_stream {
u32 id;
struct arm_smmu_master *master;
+ /*
+ * ref_count > 1 means multiple masters share this SID. Protected by
+ * smmu->streams_mutex.
+ */
+ unsigned int ref_count;
+ /*
+ * When ref_count > 1 the STE has already been written by the first
+ * master; subsequent masters must skip the write.
+ */
+ bool ste_installed;
+ /*
+ * Links all arm_smmu_stream objects that share the same SID across
+ * different masters. The canonical (XArray-stored) entry is the list
+ * head; non-owning sharers are linked into it. Used to transfer
+ * XArray ownership when the current owner is removed.
+ * Protected by smmu->streams_mutex.
+ */
+ struct list_head shared_link;
};
struct arm_smmu_vmaster {
@@ -1024,6 +1042,11 @@ struct arm_smmu_master {
bool ste_ats_enabled : 1;
bool stall_enabled;
bool ats_always_on;
+ /*
+ * True when at least one of this master's SIDs is shared with another
+ * master. SVA, stall and IOPF are disabled for such masters.
+ */
+ bool shared_sid;
unsigned int ssid_bits;
unsigned int iopf_refcount;
};
--
2.34.1
next prev parent reply other threads:[~2026-09-16 15:08 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-16 15:12 [PATCH RFC 0/4] iommu/arm-smmu-v3: Support shared Stream IDs Peng Fan (OSS)
2026-09-16 15:12 ` [PATCH RFC 1/4] iommu/arm-smmu-v3: Convert streams from RB tree to XArray Peng Fan (OSS)
2026-09-16 15:12 ` Peng Fan (OSS) [this message]
2026-09-16 15:12 ` [PATCH RFC 3/4] iommu/arm-smmu-v3: Group aliasing devices into the same IOMMU group Peng Fan (OSS)
2026-09-16 15:12 ` [PATCH RFC 4/4] iommu/arm-smmu-v3: Wire up shared-SID STE ordering and feature gating Peng Fan (OSS)
2026-09-16 16:10 ` [PATCH RFC 0/4] iommu/arm-smmu-v3: Support shared Stream IDs Jason Gunthorpe
2026-09-17 1:33 ` Peng Fan
2026-09-17 14:48 ` Jason Gunthorpe
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=20260916-smmu-shared-sid-v1-2-517384504aee@nxp.com \
--to=peng.fan@oss.nxp.com \
--cc=iommu@lists.linux.dev \
--cc=jgg@ziepe.ca \
--cc=joro@8bytes.org \
--cc=jpb@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=peng.fan@nxp.com \
--cc=robin.murphy@arm.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
all inboxes | Powered by JetHome®