* [PATCH RFC v2 1/4] iommu/arm-smmu-v3: Convert streams from RB tree to XArray
2026-09-21 11:34 [PATCH RFC v2 0/4] iommu/arm-smmu-v3: Support shared Stream IDs Peng Fan (OSS)
@ 2026-09-21 11:35 ` Peng Fan (OSS)
2026-09-21 19:24 ` Nicolin Chen
2026-09-21 12:38 ` [PATCH RFC v2 2/4] iommu/arm-smmu-v3: Support shared SIDs in insert/remove_master Peng Fan (OSS)
` (2 subsequent siblings)
3 siblings, 1 reply; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-09-21 11:35 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Jean-Philippe Brucker, Jason Gunthorpe
Cc: linux-arm-kernel, iommu, linux-kernel, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
Replace the smmu->streams RB tree with an XArray for SID ->
arm_smmu_stream lookups. The existing streams_mutex serialises all
accesses (both xa_store/xa_erase and xa_load), protecting the lifetime
of returned pointers against concurrent arm_smmu_remove_master()
without requiring RCU grace periods. A mutex (rather than xa_lock) is
needed because several paths sleep while the lock is held:
dmam_alloc_coherent(GFP_KERNEL) in arm_smmu_init_sid_strtab(), and
down_read() inside iommu_report_device_fault().
This removes the RB tree comparators, the rb_node from
arm_smmu_stream, and simplifies duplicate-SID handling for bridged PCI
devices.
No behavioural change intended; preparation for shared-SID support.
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 | 83 ++++++++++++++---------------
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 11 +++-
2 files changed, 48 insertions(+), 46 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 5732f3ba0122d..65e448a69a019 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2024,37 +2024,17 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
return 0;
}
-static int arm_smmu_streams_cmp_key(const void *lhs, const struct rb_node *rhs)
-{
- struct arm_smmu_stream *stream_rhs =
- rb_entry(rhs, struct arm_smmu_stream, node);
- const u32 *sid_lhs = lhs;
-
- if (*sid_lhs < stream_rhs->id)
- return -1;
- if (*sid_lhs > stream_rhs->id)
- return 1;
- return 0;
-}
-
-static int arm_smmu_streams_cmp_node(struct rb_node *lhs,
- const struct rb_node *rhs)
-{
- return arm_smmu_streams_cmp_key(
- &rb_entry(lhs, struct arm_smmu_stream, node)->id, rhs);
-}
-
static struct arm_smmu_master *
arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
{
- struct rb_node *node;
+ struct arm_smmu_stream *stream;
lockdep_assert_held(&smmu->streams_mutex);
- node = rb_find(&sid, &smmu->streams, arm_smmu_streams_cmp_key);
- if (!node)
+ stream = xa_load(&smmu->streams, sid);
+ if (!stream)
return NULL;
- return rb_entry(node, struct arm_smmu_stream, node)->master;
+ return stream->master;
}
/* IRQ and event handlers */
@@ -4123,38 +4103,47 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
NULL);
mutex_lock(&smmu->streams_mutex);
- for (i = 0; i < fwspec->num_ids; i++) {
+ for (i = 0; i < master->num_streams; i++) {
struct arm_smmu_stream *new_stream = &master->streams[i];
- struct rb_node *existing;
+ struct arm_smmu_stream *existing;
u32 sid = new_stream->id;
ret = arm_smmu_init_sid_strtab(smmu, sid);
if (ret)
break;
- /* Insert into SID tree */
- existing = rb_find_add(&new_stream->node, &smmu->streams,
- arm_smmu_streams_cmp_node);
- if (existing) {
- struct arm_smmu_master *existing_master =
- rb_entry(existing, struct arm_smmu_stream, node)
- ->master;
-
- /* Bridged PCI devices may end up with duplicated IDs */
- if (existing_master == master)
- continue;
+ /* Bridged PCI devices may end up with duplicated IDs */
+ if (i > 0 && master->streams[i - 1].id == sid)
+ continue;
+ 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));
+ sid, dev_name(existing->master->dev));
ret = -ENODEV;
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) {
- for (i--; i >= 0; i--)
- rb_erase(&master->streams[i].node, &smmu->streams);
+ for (i--; i >= 0; i--) {
+ u32 sid = master->streams[i].id;
+
+ if (i > 0 && master->streams[i - 1].id == sid)
+ continue;
+ xa_erase(&smmu->streams, sid);
+ }
kfree(master->streams);
kfree(master->build_invs);
}
@@ -4167,14 +4156,19 @@ static void arm_smmu_remove_master(struct arm_smmu_master *master)
{
int i;
struct arm_smmu_device *smmu = master->smmu;
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
if (!smmu || !master->streams)
return;
mutex_lock(&smmu->streams_mutex);
- for (i = 0; i < fwspec->num_ids; i++)
- rb_erase(&master->streams[i].node, &smmu->streams);
+ for (i = 0; i < master->num_streams; i++) {
+ u32 sid = master->streams[i].id;
+
+ /* Skip intra-master duplicate SIDs */
+ if (i > 0 && master->streams[i - 1].id == sid)
+ continue;
+ xa_erase(&smmu->streams, sid);
+ }
mutex_unlock(&smmu->streams_mutex);
kfree(master->streams);
@@ -4602,7 +4596,7 @@ static int arm_smmu_init_structures(struct arm_smmu_device *smmu)
int ret;
mutex_init(&smmu->streams_mutex);
- smmu->streams = RB_ROOT;
+ xa_init(&smmu->streams);
ret = arm_smmu_init_queues(smmu);
if (ret)
@@ -5627,6 +5621,7 @@ static void arm_smmu_device_remove(struct platform_device *pdev)
iommu_device_unregister(&smmu->iommu);
iommu_device_sysfs_remove(&smmu->iommu);
+ xa_destroy(&smmu->streams);
}
static void arm_smmu_device_shutdown(struct platform_device *pdev)
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 dd2fee2f560e6..97dc97ac704d9 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/mmzone.h>
#include <linux/sizes.h>
+#include <linux/xarray.h>
struct arm_smmu_device;
struct arm_vsmmu;
@@ -961,14 +962,20 @@ struct arm_smmu_device {
/* IOMMU core code handle */
struct iommu_device iommu;
- struct rb_root streams;
+ /*
+ * XArray of arm_smmu_stream, indexed by SID.
+ * All accesses (reads and writes) are serialised by streams_mutex.
+ * The mutex is held across xa_load() and all subsequent uses of the
+ * returned pointer to prevent use-after-free from concurrent
+ * arm_smmu_remove_master().
+ */
+ struct xarray streams;
struct mutex streams_mutex;
};
struct arm_smmu_stream {
u32 id;
struct arm_smmu_master *master;
- struct rb_node node;
};
struct arm_smmu_vmaster {
--
2.34.1
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH RFC v2 1/4] iommu/arm-smmu-v3: Convert streams from RB tree to XArray
2026-09-21 11:35 ` [PATCH RFC v2 1/4] iommu/arm-smmu-v3: Convert streams from RB tree to XArray Peng Fan (OSS)
@ 2026-09-21 19:24 ` Nicolin Chen
2026-09-22 14:04 ` Peng Fan
0 siblings, 1 reply; 12+ messages in thread
From: Nicolin Chen @ 2026-09-21 19:24 UTC (permalink / raw)
To: Peng Fan (OSS)
Cc: Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Jean-Philippe Brucker, Jason Gunthorpe, linux-arm-kernel, iommu,
linux-kernel, Peng Fan
On Mon, Sep 21, 2026 at 07:35:00PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan@nxp.com>
>
> Replace the smmu->streams RB tree with an XArray for SID ->
> arm_smmu_stream lookups. The existing streams_mutex serialises all
> accesses (both xa_store/xa_erase and xa_load), protecting the lifetime
> of returned pointers against concurrent arm_smmu_remove_master()
> without requiring RCU grace periods. A mutex (rather than xa_lock) is
> needed because several paths sleep while the lock is held:
> dmam_alloc_coherent(GFP_KERNEL) in arm_smmu_init_sid_strtab(), and
> down_read() inside iommu_report_device_fault().
The commit message reads very unconvincing.
The first paragraph starts with an action "replace" without giving
a clear reason for the action.
> This removes the RB tree comparators, the rb_node from
Then the second paragraph repeats the action...
> arm_smmu_stream, and simplifies duplicate-SID handling for bridged PCI
> devices.
... and slightly mentions "simplifies". Maybe it should write about
why this is necessary and how xarray would simplify vs RB tree?
Nicolin
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH RFC v2 1/4] iommu/arm-smmu-v3: Convert streams from RB tree to XArray
2026-09-21 19:24 ` Nicolin Chen
@ 2026-09-22 14:04 ` Peng Fan
2026-09-22 16:56 ` Nicolin Chen
0 siblings, 1 reply; 12+ messages in thread
From: Peng Fan @ 2026-09-22 14:04 UTC (permalink / raw)
To: Nicolin Chen
Cc: Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Jean-Philippe Brucker, Jason Gunthorpe, linux-arm-kernel, iommu,
linux-kernel, Peng Fan
Hi Nicolin,
Thanks for reviewing.
On Mon, Sep 21, 2026 at 12:24:13PM -0700, Nicolin Chen wrote:
>On Mon, Sep 21, 2026 at 07:35:00PM +0800, Peng Fan (OSS) wrote:
>> From: Peng Fan <peng.fan@nxp.com>
>>
>> Replace the smmu->streams RB tree with an XArray for SID ->
>> arm_smmu_stream lookups. The existing streams_mutex serialises all
>> accesses (both xa_store/xa_erase and xa_load), protecting the lifetime
>> of returned pointers against concurrent arm_smmu_remove_master()
>> without requiring RCU grace periods. A mutex (rather than xa_lock) is
>> needed because several paths sleep while the lock is held:
>> dmam_alloc_coherent(GFP_KERNEL) in arm_smmu_init_sid_strtab(), and
>> down_read() inside iommu_report_device_fault().
>
>The commit message reads very unconvincing.
>
>The first paragraph starts with an action "replace" without giving
>a clear reason for the action.
>
>> This removes the RB tree comparators, the rb_node from
>
>Then the second paragraph repeats the action...
>
>> arm_smmu_stream, and simplifies duplicate-SID handling for bridged PCI
>> devices.
>
>... and slightly mentions "simplifies". Maybe it should write about
>why this is necessary and how xarray would simplify vs RB tree?
Jean had a comment that "maybe simplify the driver first by moving to a xarray",
see [1] [2].
[1] https://lore.kernel.org/linux-iommu/20230518130459.GA2587493@myrica/
[2] https://lore.kernel.org/linux-iommu/ecb3725c-27c4-944b-b42c-f4e293521f94@arm.com/#t
Does below commit message looks good to you?
iommu/arm-smmu-v3: Convert streams from RB tree to XArray
As suggested by Jean-Philippe Brucker [1], convert the smmu->streams
RB tree to an XArray as a preparatory simplification for shared-SID
support.
A subsequent patch needs to look up an existing stream by SID and
then decide to share it rather than reject it - two separate
operations. The RB tree's rb_find_add() fuses lookup and insertion
atomically: it either inserts or returns the collision, making
"find, then conditionally share" impossible without restructuring.
XArray's xa_load() and xa_store() are independent operations that
naturally support this pattern.
Eliminates the two comparator functions (arm_smmu_streams_cmp_key/node),
the per-stream rb_node field.
The existing streams_mutex continues to serialise all accesses. A
mutex (rather than xa_lock) is needed because several paths sleep
while the lock is held: dmam_alloc_coherent(GFP_KERNEL) in
arm_smmu_init_sid_strtab(), and down_read() inside
iommu_report_device_fault().
No behavioural change.
[1] https://lore.kernel.org/linux-iommu/20230518130459.GA2587493@myrica/#t
Thanks,
Peng
>
>Nicolin
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH RFC v2 1/4] iommu/arm-smmu-v3: Convert streams from RB tree to XArray
2026-09-22 14:04 ` Peng Fan
@ 2026-09-22 16:56 ` Nicolin Chen
0 siblings, 0 replies; 12+ messages in thread
From: Nicolin Chen @ 2026-09-22 16:56 UTC (permalink / raw)
To: Peng Fan
Cc: Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Jean-Philippe Brucker, Jason Gunthorpe, linux-arm-kernel, iommu,
linux-kernel, Peng Fan
On Tue, Sep 22, 2026 at 10:04:39PM +0800, Peng Fan wrote:
> >... and slightly mentions "simplifies". Maybe it should write about
> >why this is necessary and how xarray would simplify vs RB tree?
>
> Jean had a comment that "maybe simplify the driver first by moving to a xarray",
> see [1] [2].
>
> [1] https://lore.kernel.org/linux-iommu/20230518130459.GA2587493@myrica/
> [2] https://lore.kernel.org/linux-iommu/ecb3725c-27c4-944b-b42c-f4e293521f94@arm.com/#t
You should have put a suggested-by tag and likely one of the links
as well.
With that being said, I don't see the reasoning in those emails very
convincing either. I don't dislike xarray. Yet in this series, there
seems no compelling reason on switching RB tree to xarray.
> A subsequent patch needs to look up an existing stream by SID and
> then decide to share it rather than reject it - two separate
> operations. The RB tree's rb_find_add() fuses lookup and insertion
> atomically: it either inserts or returns the collision, making
> "find, then conditionally share" impossible without restructuring.
> XArray's xa_load() and xa_store() are independent operations that
> naturally support this pattern.
If you avoid duplicated stream structures as I suggested in PATCH-2,
there is no need of that, since you would only insert once to the RB
tree.
Nicolin
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH RFC v2 2/4] iommu/arm-smmu-v3: Support shared SIDs in insert/remove_master
2026-09-21 11:34 [PATCH RFC v2 0/4] iommu/arm-smmu-v3: Support shared Stream IDs Peng Fan (OSS)
2026-09-21 11:35 ` [PATCH RFC v2 1/4] iommu/arm-smmu-v3: Convert streams from RB tree to XArray Peng Fan (OSS)
@ 2026-09-21 12:38 ` Peng Fan (OSS)
2026-09-21 23:15 ` Nicolin Chen
2026-09-21 12:40 ` [PATCH RFC v2 3/4] iommu/arm-smmu-v3: Group aliasing devices into the same IOMMU group Peng Fan (OSS)
2026-09-21 12:41 ` [PATCH RFC v2 4/4] iommu/arm-smmu-v3: Wire up shared-SID STE ordering and feature gating Peng Fan (OSS)
3 siblings, 1 reply; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-09-21 12:38 UTC (permalink / raw)
To: will, robin.murphy, joro, jpb, jgg
Cc: linux-arm-kernel, iommu, linux-kernel, peng.fan
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
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH RFC v2 2/4] iommu/arm-smmu-v3: Support shared SIDs in insert/remove_master
2026-09-21 12:38 ` [PATCH RFC v2 2/4] iommu/arm-smmu-v3: Support shared SIDs in insert/remove_master Peng Fan (OSS)
@ 2026-09-21 23:15 ` Nicolin Chen
2026-09-22 14:13 ` Peng Fan
0 siblings, 1 reply; 12+ messages in thread
From: Nicolin Chen @ 2026-09-21 23:15 UTC (permalink / raw)
To: Peng Fan (OSS)
Cc: will, robin.murphy, joro, jpb, jgg, linux-arm-kernel, iommu,
linux-kernel, peng.fan
On Mon, Sep 21, 2026 at 08:38:46PM +0800, Peng Fan (OSS) wrote:
> @@ -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;
> };
SID-sharing masters still allocate their own streams. Though the
SIDs are the same number, they own duplicated streams linked via
that "shared_link" list.
master_a->stream[0] --> stream (SID=X) --|
shared_link
master_b->stream[0] --> stream (SID=X) --|
But maybe they could share the stream structure directly? I.e.
master_a->stream[0] --|
|--> shared stream (SID=X)
master_b->stream[0] --|
The stream structure would still need a list for shared_masters:
struct arm_smmu_stream {
[...]
/* Every sharing master, ->master included. Empty unless shared */
struct list_head shared_masters;
};
ref_count could be simply !list_empty(&stream->shared_masters).
Does i.MX need to support SID-sharing with multi-SD device? If not,
the master could have only a simple shared_masters_elm:
struct arm_smmu_master {
[....]
/* Supports num_streams == 1 only. Empty if SID is not shared */
struct list_head shared_masters_elm;
};
> @@ -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;
Then, this could be !list_empty(&master->shared_masters_elm).
Nicolin
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH RFC v2 2/4] iommu/arm-smmu-v3: Support shared SIDs in insert/remove_master
2026-09-21 23:15 ` Nicolin Chen
@ 2026-09-22 14:13 ` Peng Fan
2026-09-22 15:52 ` Robin Murphy
0 siblings, 1 reply; 12+ messages in thread
From: Peng Fan @ 2026-09-22 14:13 UTC (permalink / raw)
To: Nicolin Chen
Cc: will, robin.murphy, joro, jpb, jgg, linux-arm-kernel, iommu,
linux-kernel, peng.fan
On Mon, Sep 21, 2026 at 04:15:18PM -0700, Nicolin Chen wrote:
>On Mon, Sep 21, 2026 at 08:38:46PM +0800, Peng Fan (OSS) wrote:
>> @@ -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;
>> };
>
>SID-sharing masters still allocate their own streams. Though the
>SIDs are the same number, they own duplicated streams linked via
>that "shared_link" list.
>
> master_a->stream[0] --> stream (SID=X) --|
> shared_link
> master_b->stream[0] --> stream (SID=X) --|
>
>But maybe they could share the stream structure directly? I.e.
>
> master_a->stream[0] --|
> |--> shared stream (SID=X)
> master_b->stream[0] --|
>
>
>The stream structure would still need a list for shared_masters:
>
>struct arm_smmu_stream {
>[...]
> /* Every sharing master, ->master included. Empty unless shared */
> struct list_head shared_masters;
>};
>
>ref_count could be simply !list_empty(&stream->shared_masters).
Agree.
>
>
>Does i.MX need to support SID-sharing with multi-SD device? If not,
>the master could have only a simple shared_masters_elm:
For i.MX, there is no need to support SID sharing for multi-SID device for now.
Not sure, in future there are cases that needs SID sharing for multi-SID device.
I could update in V3 following your suggestion.
Thanks,
Peng
>
>struct arm_smmu_master {
>[....]
> /* Supports num_streams == 1 only. Empty if SID is not shared */
> struct list_head shared_masters_elm;
>};
>
>> @@ -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;
>
>Then, this could be !list_empty(&master->shared_masters_elm).
>
>Nicolin
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH RFC v2 2/4] iommu/arm-smmu-v3: Support shared SIDs in insert/remove_master
2026-09-22 14:13 ` Peng Fan
@ 2026-09-22 15:52 ` Robin Murphy
2026-09-22 17:47 ` Nicolin Chen
0 siblings, 1 reply; 12+ messages in thread
From: Robin Murphy @ 2026-09-22 15:52 UTC (permalink / raw)
To: Peng Fan, Nicolin Chen
Cc: will, joro, jpb, jgg, linux-arm-kernel, iommu, linux-kernel, peng.fan
On 22/09/2026 3:13 pm, Peng Fan wrote:
> On Mon, Sep 21, 2026 at 04:15:18PM -0700, Nicolin Chen wrote:
>> On Mon, Sep 21, 2026 at 08:38:46PM +0800, Peng Fan (OSS) wrote:
>>> @@ -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;
>>> };
>>
>> SID-sharing masters still allocate their own streams. Though the
>> SIDs are the same number, they own duplicated streams linked via
>> that "shared_link" list.
>>
>> master_a->stream[0] --> stream (SID=X) --|
>> shared_link
>> master_b->stream[0] --> stream (SID=X) --|
>>
>> But maybe they could share the stream structure directly? I.e.
>>
>> master_a->stream[0] --|
>> |--> shared stream (SID=X)
>> master_b->stream[0] --|
>>
>>
>> The stream structure would still need a list for shared_masters:
>>
>> struct arm_smmu_stream {
>> [...]
>> /* Every sharing master, ->master included. Empty unless shared */
>> struct list_head shared_masters;
>> };
>>
>> ref_count could be simply !list_empty(&stream->shared_masters).
>
> Agree.
>
>>
>>
>> Does i.MX need to support SID-sharing with multi-SD device? If not,
>> the master could have only a simple shared_masters_elm:
>
> For i.MX, there is no need to support SID sharing for multi-SID device for now.
> Not sure, in future there are cases that needs SID sharing for multi-SID device.
I have a system meeting those conditions :)
Specifically, I have a physical PCIe-to-PCI bridge board with a couple
of ancient cards plugged into it (such that they each end up with their
own RID plus the common bridge alias RID) just in case I ever got round
to looking at this myself...
(And for added fun, one of the cards only supports 31-bit DMA and the
machine doesn't have any RAM low enough for it to work without the SMMU
at all)
Cheers,
Robin.
>
> I could update in V3 following your suggestion.
>
> Thanks,
> Peng
>
>>
>> struct arm_smmu_master {
>> [....]
>> /* Supports num_streams == 1 only. Empty if SID is not shared */
>> struct list_head shared_masters_elm;
>> };
>>
>>> @@ -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;
>>
>> Then, this could be !list_empty(&master->shared_masters_elm).
>>
>> Nicolin
>>
>>
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH RFC v2 2/4] iommu/arm-smmu-v3: Support shared SIDs in insert/remove_master
2026-09-22 15:52 ` Robin Murphy
@ 2026-09-22 17:47 ` Nicolin Chen
0 siblings, 0 replies; 12+ messages in thread
From: Nicolin Chen @ 2026-09-22 17:47 UTC (permalink / raw)
To: Robin Murphy
Cc: Peng Fan, will, joro, jpb, jgg, linux-arm-kernel, iommu,
linux-kernel, peng.fan
On Tue, Sep 22, 2026 at 04:52:35PM +0100, Robin Murphy wrote:
> On 22/09/2026 3:13 pm, Peng Fan wrote:
> > On Mon, Sep 21, 2026 at 04:15:18PM -0700, Nicolin Chen wrote:
> > > Does i.MX need to support SID-sharing with multi-SD device? If not,
> > > the master could have only a simple shared_masters_elm:
> >
> > For i.MX, there is no need to support SID sharing for multi-SID device for now.
> > Not sure, in future there are cases that needs SID sharing for multi-SID device.
>
> I have a system meeting those conditions :)
>
> Specifically, I have a physical PCIe-to-PCI bridge board with a couple of
> ancient cards plugged into it (such that they each end up with their own RID
> plus the common bridge alias RID) just in case I ever got round to looking
> at this myself...
Though in such cases we cannot reject num_streams != 1 any more,
that bridge can still end up with one single shared stream, e.g.
alias = PCI_DEVID(0x02, PCI_DEVFN(0,0)) = 0x0200
Card A = 02:01.0 -> sorted SIDs { 0x0200, 0x0208 }
Card B = 02:02.0 -> sorted SIDs { 0x0200, 0x0210 }
?
Hopefully, we won't have to support an ancient PCIe-to-PCI bridge
connecting with another ancient PCI-to-PCI bridge...
Nicolin
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH RFC v2 3/4] iommu/arm-smmu-v3: Group aliasing devices into the same IOMMU group
2026-09-21 11:34 [PATCH RFC v2 0/4] iommu/arm-smmu-v3: Support shared Stream IDs Peng Fan (OSS)
2026-09-21 11:35 ` [PATCH RFC v2 1/4] iommu/arm-smmu-v3: Convert streams from RB tree to XArray Peng Fan (OSS)
2026-09-21 12:38 ` [PATCH RFC v2 2/4] iommu/arm-smmu-v3: Support shared SIDs in insert/remove_master Peng Fan (OSS)
@ 2026-09-21 12:40 ` Peng Fan (OSS)
2026-09-21 12:41 ` [PATCH RFC v2 4/4] iommu/arm-smmu-v3: Wire up shared-SID STE ordering and feature gating Peng Fan (OSS)
3 siblings, 0 replies; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-09-21 12:40 UTC (permalink / raw)
To: will, robin.murphy, joro, jpb, jgg
Cc: linux-arm-kernel, iommu, linux-kernel, peng.fan
From: Peng Fan <peng.fan@nxp.com>
arm_smmu_device_group() previously rejected SID aliasing with a comment
saying it was impractical. Now that the XArray makes SID lookup O(1),
detect aliasing at group-assignment time and place the new device into
the same IOMMU group as the master that already owns the SID.
This is a prerequisite for shared-SID support: devices sharing a SID
must share a single IOMMU domain and therefore a single cd_table,
because the STE can only point to one cd_table at a time.
arm_smmu_device_group() is called before arm_smmu_insert_master() adds
the current master's streams to the xarray, so any xarray hit here
belongs to a different, already-probed master. streams_mutex is held
to ensure the xarray is stable and the returned stream object is not
freed concurrently.
If a device has multiple SIDs that land in different existing groups, a
warning is emitted. The IOMMU core has no group-merge API, so this
cannot be fixed up and DMA isolation may be compromised.
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 | 61 ++++++++++++++++++---
1 file changed, 53 insertions(+), 8 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 f53e1871426a5..bb3ee25d10d6e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4365,19 +4365,64 @@ static int arm_smmu_set_dirty_tracking(struct iommu_domain *domain,
static struct iommu_group *arm_smmu_device_group(struct device *dev)
{
- struct iommu_group *group;
+ struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+ struct arm_smmu_device *smmu = master->smmu;
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+ struct iommu_group *group = NULL;
+ int i;
/*
- * We don't support devices sharing stream IDs other than PCI RID
- * aliases, since the necessary ID-to-device lookup becomes rather
- * impractical given a potential sparse 32-bit stream ID space.
+ * If any of this device's SIDs are already owned by another master,
+ * place this device in the same IOMMU group as that master. This
+ * ensures that aliasing devices share a single domain and therefore
+ * a single cd_table, which is required because the STE can only
+ * point to one cd_table at a time.
+ *
+ * arm_smmu_device_group() is called before arm_smmu_insert_master()
+ * adds the current master's streams to the xarray, so any hit here
+ * belongs to a different, already-probed master.
+ *
+ * streams_mutex is held to ensure the xarray is stable and the
+ * returned stream object is not freed concurrently.
*/
+ mutex_lock(&smmu->streams_mutex);
+ for (i = 0; i < fwspec->num_ids; i++) {
+ struct arm_smmu_stream *stream =
+ xa_load(&smmu->streams, fwspec->ids[i]);
+ struct iommu_group *existing;
+
+ if (!stream)
+ continue;
+
+ existing = iommu_group_get(stream->master->dev);
+ if (!group) {
+ group = existing;
+ } else if (group != existing) {
+ /*
+ * This device has SIDs in two different groups.
+ * The IOMMU core has no group-merge API, so we
+ * cannot fix this up. Warn and keep the first
+ * group — the mismatched SID will still be
+ * inserted into the XArray and shared, but DMA
+ * isolation is compromised.
+ */
+ dev_warn(dev,
+ "SID 0x%x already in a different IOMMU group than SID 0x%x, expect broken isolation\n",
+ fwspec->ids[i], fwspec->ids[0]);
+ iommu_group_put(existing);
+ } else {
+ iommu_group_put(existing);
+ }
+ }
+ mutex_unlock(&smmu->streams_mutex);
+
+ if (group)
+ return group;
+
if (dev_is_pci(dev))
- group = pci_device_group(dev);
- else
- group = generic_device_group(dev);
+ return pci_device_group(dev);
- return group;
+ return generic_device_group(dev);
}
static int arm_smmu_of_xlate(struct device *dev,
--
2.34.1
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH RFC v2 4/4] iommu/arm-smmu-v3: Wire up shared-SID STE ordering and feature gating
2026-09-21 11:34 [PATCH RFC v2 0/4] iommu/arm-smmu-v3: Support shared Stream IDs Peng Fan (OSS)
` (2 preceding siblings ...)
2026-09-21 12:40 ` [PATCH RFC v2 3/4] iommu/arm-smmu-v3: Group aliasing devices into the same IOMMU group Peng Fan (OSS)
@ 2026-09-21 12:41 ` Peng Fan (OSS)
3 siblings, 0 replies; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-09-21 12:41 UTC (permalink / raw)
To: will, robin.murphy, joro, jpb, jgg
Cc: linux-arm-kernel, iommu, linux-kernel, peng.fan
From: Peng Fan <peng.fan@nxp.com>
For shared SIDs, only the first master to attach writes the STE
(tracked by ste_installed under streams_mutex); subsequent masters
skip the write. On teardown, only the last master writes the ABORT
STE (ref_count == 1). This is handled by arm_smmu_skip_shared_ste().
Fault events on shared SIDs cannot be attributed to a specific master,
so arm_smmu_find_master() returns NULL when ref_count > 1.
Disable SVA, IOPF/stall, and vSMMU nesting for shared-SID masters
since all three require unambiguous SID-to-device mapping.
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
.../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 4 +-
.../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 7 +++
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 59 +++++++++++++++++--
3 files changed, 65 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
index ab1078a97d801..258ca42917f07 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
@@ -308,8 +308,10 @@ static int arm_vsmmu_vdevice_init(struct iommufd_vdevice *vdev)
/*
* arm_vsmmu_vsid_to_sid() maps a vSID to master->streams[0] alone, so
* more streams would leave the rest stale and none reads out of bounds.
+ * Shared SIDs are also unsupported for vSMMU since the STE is shared
+ * between multiple masters.
*/
- if (master->num_streams != 1)
+ if (master->num_streams != 1 || master->shared_sid)
return -EOPNOTSUPP;
return 0;
}
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 0a429c64fbf3e..43f8cc81bfdd1 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -271,6 +271,13 @@ static int arm_smmu_sva_set_dev_pasid(struct iommu_domain *domain,
if (!(master->smmu->features & ARM_SMMU_FEAT_SVA))
return -EOPNOTSUPP;
+ /*
+ * SVA requires stall-based fault handling which cannot be supported
+ * when multiple devices share a SID (fault routing is ambiguous).
+ */
+ if (master->shared_sid)
+ return -EOPNOTSUPP;
+
/* Prevent arm_smmu_mm_release from being called while we are attaching */
if (!mmget_not_zero(domain->mm))
return -EINVAL;
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 bb3ee25d10d6e..13968191b1452 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2034,6 +2034,13 @@ arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
stream = xa_load(&smmu->streams, sid);
if (!stream)
return NULL;
+ /*
+ * For shared SIDs (ref_count > 1) we cannot determine which master
+ * triggered the fault, so return NULL to let the caller handle it
+ * as an unresolvable event.
+ */
+ if (stream->ref_count > 1)
+ return NULL;
return stream->master;
}
@@ -2944,11 +2951,43 @@ arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
}
}
+/*
+ * For shared SIDs, check whether this master should skip the STE write.
+ *
+ * Setup path: only the first master writes the STE; subsequent masters
+ * skip because ste_installed is already true.
+ *
+ * Teardown path (ABORT): skip while other masters still share the SID
+ * (ref_count > 1). Only the last remaining master writes the ABORT STE.
+ *
+ * Returns true if the STE write should be skipped for this SID.
+ */
+static bool arm_smmu_skip_shared_ste(struct arm_smmu_device *smmu,
+ u32 sid, bool is_abort)
+{
+ struct arm_smmu_stream *stream;
+ bool skip = false;
+
+ mutex_lock(&smmu->streams_mutex);
+ stream = xa_load(&smmu->streams, sid);
+ if (stream) {
+ if (is_abort)
+ skip = stream->ref_count > 1;
+ else if (stream->ste_installed)
+ skip = true;
+ else
+ stream->ste_installed = true;
+ }
+ mutex_unlock(&smmu->streams_mutex);
+ return skip;
+}
+
void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master,
const struct arm_smmu_ste *target)
{
int i, j;
struct arm_smmu_device *smmu = master->smmu;
+ bool is_abort;
master->cd_table.in_ste =
FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(target->data[0])) ==
@@ -2957,10 +2996,12 @@ void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master,
FIELD_GET(STRTAB_STE_1_EATS, le64_to_cpu(target->data[1])) ==
STRTAB_STE_1_EATS_TRANS;
+ is_abort = (FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(target->data[0])) ==
+ STRTAB_STE_0_CFG_ABORT);
+
for (i = 0; i < master->num_streams; ++i) {
u32 sid = master->streams[i].id;
- struct arm_smmu_ste *step =
- arm_smmu_get_step_for_sid(smmu, sid);
+ struct arm_smmu_ste *step;
/* Bridged PCI devices may end up with duplicated IDs */
for (j = 0; j < i; j++)
@@ -2969,6 +3010,11 @@ void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master,
if (j < i)
continue;
+ if (master->shared_sid &&
+ arm_smmu_skip_shared_ste(smmu, sid, is_abort))
+ continue;
+
+ step = arm_smmu_get_step_for_sid(smmu, sid);
arm_smmu_write_ste(master, sid, step, target);
}
}
@@ -3116,8 +3162,13 @@ static int arm_smmu_enable_iopf(struct arm_smmu_master *master,
if (!master->stall_enabled)
return 0;
- /* We're not keeping track of SIDs in fault events */
- if (master->num_streams != 1)
+ /*
+ * We're not keeping track of SIDs in fault events, and stall/PRI
+ * cannot be supported when multiple devices share a SID because page
+ * fault responses are routed by RID/SID and we cannot distinguish
+ * which device triggered the fault.
+ */
+ if (master->num_streams != 1 || master->shared_sid)
return -EOPNOTSUPP;
if (master->iopf_refcount) {
--
2.34.1
^ permalink raw reply [flat|nested] 12+ messages in thread