mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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


  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®