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>,
Nicolin Chen <nicolinc@nvidia.com>,
Jason Gunthorpe <jgg@ziepe.ca>,
Thierry Reding <thierry.reding@kernel.org>,
Krishna Reddy <vdumpa@nvidia.com>,
Jonathan Hunter <jonathanh@nvidia.com>,
Jason Gunthorpe <jgg@ziepe.ca>
Cc: 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: [PATCH RFC v8 0/9] iommu/arm-smmu-v3: Support shared Stream IDs
Date: Fri, 13 Nov 2026 21:27:12 +0800 [thread overview]
Message-ID: <20261113-b4-smmu-shared-sid-ver8-v8-0-587307a77f3a@nxp.com> (raw)
Changes since RFC v7:
- Add a locking patch that serializes shared-SID membership changes with
attach/PASID/ATS/vSMMU using arm_smmu_asid_lock. The lock order remains
asid_lock -> streams_mutex; arm_smmu_set_pasid() rechecks membership
under asid_lock, and the vSMMU checks in iommufd and Tegra241 vINTF are
moved under asid_lock.
- Add a PASID teardown patch that quiesces the PASID before mmu_notifier
release can unlink it. Clear the CD and invalidate ATS before removing
master_domain, use a no-account CD write from arm_smmu_mm_release(), and
re-clear the CD without accounting after unlinking. This closes the
exit_mmap() use-after-free window and the used_ssids resurrection race.
- Fold the CD[0] allocation fix into the per-domain CD table patch:
allocate CD[0] as part of arm_smmu_master_alloc_cd_tables(), factor the
L2 allocation into arm_smmu_alloc_cd_ptr_l2(), and free/reset the new
table if CD[0] allocation fails. A later identity/blocked/stage-2 attach
can no longer find an allocated table with a missing CD[0] and warn in
arm_smmu_clear_cd().
- Fold the in_ste fix into the per-domain CD table patch. in_ste now means
the STE actually walks the private CD table, not merely that the STE is
S1-translate. This removes the "first" special case from set_pasid and
moves the redundant-STE-write guard back into arm_smmu_update_ste().
- Separate the per-device release domain from the group-wide blocked
domain. A shared SID skips the release STE only while other sharers
remain; a group-wide blocked attach still programs the abort STE.
- Complete the vSMMU gating for shared SIDs. In addition to
arm_vsmmu_vdevice_init(), check arm_smmu_master_shares_sid() in
tegra241_vintf_init_vsid(), arm_smmu_get_viommu_size(), and
arm_smmu_attach_dev_nested(), and reject sharing with an existing master
that already has a vmaster.
- Split ATS capability from ATS support. arm_smmu_ats_capable() describes
hardware/PCIe capability; arm_smmu_ats_supported() also requires that
the SID is not shared. Shared ATS-capable devices are prepared through
pci_prepare_ats() but ATS is not enabled. Existing masters with ATS
enabled, ATS-always-on, PASID, or vSMMU state reject new sharers.
- Reject shared-SID configurations that cannot be supported safely:
multi-SID masters, stalling on either side, incoming ATS-required
devices, and PCI/non-PCI SID aliasing.
- Resolve stall_enabled before insert_master() and use
master->stall_enabled directly for CD.S, STE.S1STALLD, and STE.S2S.
Remove the redundant arm_smmu_master_stall_enabled() helper and rename
arm_smmu_is_shared_sid() to arm_smmu_master_shares_sid().
- Do not propagate attach_dev() failures when dropping the last PASID.
The S1 RID domain now uses the same ignore-return policy as the old
identity/blocked downgrade path; the private CD table is kept for reuse.
- Propagate arm_smmu_attach_prepare() failures from the identity, blocked,
and release attach paths instead of installing a partially prepared STE.
- Fold the CD table allocation check into the free helper, add
arm_smmu_master_needs_private_cdtab(), drop the trivial master/domain
free wrappers in favour of arm_smmu_free_cd_tables(), and rename the CD
helpers:
arm_smmu_master_alloc_cd_tables()
arm_smmu_domain_alloc_cd_tables()
arm_smmu_master_get_cd_ptr()
arm_smmu_get_cd_ptr()
- Restore the normal group return style, remove the unused downgrade
boolean, and keep the S1/identity/blocked handling under the equivalent
!ats_always_on gate.
Changes since RFC v6:
- Add "Plumb the CD table into the CD helpers" as a preparation patch, then
introduce a per-domain CD table for non-PASID S1 streams. Normal non-PASID
devices in one domain now share a single CD table; private tables are kept
only for PASID, ATS-always-on, and stalling devices.
- Rework shared-SID STE handling. With the domain-owned CD table, all sharers
build the same S1ContextPtr, so any sharer may program a normal domain STE.
Release/blocked STE writes are skipped while the SID is shared, and the last
master tears the STE down.
- Keep CD.S per-device rather than deriving it from the SMMU stall capability.
Stall-capable masters use their private CD table so CD.S, STE.S1STALLD and
STE.S2S remain consistent.
- Add arm_smmu_master_stall_enabled() and use it uniformly. Reject sharing if
either master wants stalling, and resolve the stall policy before
insert_master() so the incoming master's policy is visible.
- Reject sharing when the existing master has ATS, PASID, or stall enabled.
Disable ATS, PASID, SVA, vSMMU and IOPF for shared SIDs.
- Link to v6: https://lore.kernel.org/linux-iommu/20261011-smmu-shared-sid-v6-0-cb76b89dc612@nxp.com/
Changes since RFC v5:
- Actively deduplicate Stream IDs during insertion instead of
storing duplicate pointers. num_streams now reflects the unique
count, eliminating pointer-equality dedup loops from all cleanup
paths (Robin).
- Extracted arm_smmu_find_stream() into patch 2 instead of patch 3
to clean up the find-before-allocate code (Nicolin).
- Extracted arm_smmu_free_master_streams() helper shared between
error rollback and arm_smmu_remove_master() (Nicolin).
- Fixed remove_master to reassign stream->master when the current
owner departs, preventing dangling pointer (Nicolin).
- Fixed remove_master to use a for loop iterating master->streams[]
with per-stream shared vs non-shared handling (Nicolin).
- Reset ste_installed on ABORT so domain transitions (e.g. DMA ->
VFIO) correctly re-write the STE instead of freezing it.
- Clear stall_enabled on the first master retroactively when
sharing is detected in arm_smmu_insert_master(), not just on
subsequent masters at probe time. Prevents bus lockup when
the first master probes before sharing is known.
- Link to v5: https://lore.kernel.org/linux-iommu/20261006-smmu-shared-sid-v5-0-169a59c671d3@nxp.com/
Changes since RFC v4:
- Include Nicolin's patch ("iommu/arm-smmu-v3: Don't rb_erase() a
never-inserted stream node") to avoid conflicts in future.
so the standalone patch 1 from v4 is dropped.
- Split old patch 2 (shared SID support) into two:
- New patch 2: Convert streams from embedded array to individually
allocated objects (struct arm_smmu_stream ** instead of *).
- New patch 3: Move stream allocation inside the mutex and look up
existing entries first (find-before-allocate), avoiding unnecessary
allocation when the SID already exists. Pure refactor, no
functional change.
- New patch 4: Add shared-SID logic on top of the refactored code.
- Duplicate-SID cleanup (bridged PCI) now uses pointer-equality dedup
instead of RB_EMPTY_NODE checks, since streams are no longer
pre-allocated with cleared nodes.
- Link to v4: https://lore.kernel.org/all/20261001-smmu-shared-sid-ver3-v4-0-06b34fb2e691@nxp.com/
Changes since RFC v3:
- Added a standalone bugfix for duplicate-SID rb_erase (new patch 1).
- Stream structures are now shared directly between masters
instead of duplicating them (Nicolin). No ref_count field;
sharing is detected via list_empty(&stream->shared_masters).
- On owner removal, use rb_replace_node() + list_splice_init()
to transfer the RB tree entry and shared_masters list to the
next sharer, avoiding use-after-free.
- INIT_LIST_HEAD(&stream->shared_masters) moved after sort() to
avoid list pointer corruption from bitwise memory swaps.
- Both sides of the sharing pair are checked for num_streams == 1.
- Link to v3: https://lore.kernel.org/all/20260930-smmu-shared-sid-v3-0-8abe6c1b4c20@nxp.com/
Changes since RFC v2:
- Dropped the RB tree to XArray conversion patch (Nicolin).
The RB tree is retained as-is; a new arm_smmu_find_stream()
helper provides stream-level lookup.
- No per-master shared_sid bool; replaced by
list_empty(&master->shared_masters_elm) (Nicolin).
- Only SID-sharing for single SID device
- Follow Nicolin's suggestion https://lore.kernel.org/linux-iommu/arG6hmng3NddGEHm@nvidia.com/
- Link to v2: https://lore.kernel.org/linux-iommu/20260921-smmu-shared-sid-v2-0-4b656ce68178@nxp.com/
Changes since RFC v1:
- Revised cover letter to drop eDMA channel example (Jason).
Some SoCs have a limited number of IOMMU Stream IDs (SIDs) and
hardware that inherently shares them. For example, the NXP i.MX95
only has 64 SIDs, only 6 bits for SID in the system chip bus.
However there are many device IPs, such as SDHC, PCIE, NETC, GPU,
NPU, Display, VPU, ISP, ISI, JPEG, SATA, DMA and etc. Each Kind IP has
mutilple instances inside the SoC. So I introudce this patchset to
support shared SID.
The current ARM SMMUv3 driver rejects this with:
"Aliasing StreamID unsupported, expect DMA to be broken"
I took comments in [1] and implement this patchset and only want to
support a very simple case that multiple platform devices share one SID.
Patch 1-3 are preparatory refactoring:
- allocate stream objects individually so multiple masters can point to
the same stream;
- delay stream allocation into the streams_mutex-protected insertion
loop, reusing an existing stream when the SID is already present;
- plumb struct arm_smmu_ctx_desc_cfg through the CD helpers instead of
always deriving it from the master.
Patch 4 moves non-PASID stage-1 streams to a per-domain CD table. The
private per-master CD table is retained only for PASID substreams,
ATS-always-on/S1DSS, and the stall model. It also allocates CD[0] together
with the private table and tracks private-table use in in_ste.
Patch 5 and patch 6 add the shared-SID object model:
- link masters that use the same SID through stream->shared_masters;
- keep the stream and its RB-tree entry alive until the last master goes
away;
- transfer stream ownership when the owner is removed;
- group aliasing devices into the same IOMMU group.
Patch 7 wires up shared-SID STE programming and feature gating:
- separate the per-device release domain from the group-wide blocked
domain, so a single-device release cannot abort a shared STE while
other sharers remain;
- let any sharer program the common normal-domain STE;
- disable PASID, ATS, vSMMU, SVA, and IOPF/stall for shared SIDs;
- prepare ATS for shared ATS-capable devices without enabling it;
- reject ATS-required devices, PCI/non-PCI mixing, multi-SID masters,
and stalling configurations.
Patch 8 serializes shared-SID membership changes with the attach/PASID/ATS
and vSMMU paths using arm_smmu_asid_lock, keeping the lock order as
arm_smmu_asid_lock -> streams_mutex.
Patch 9 fixes the PASID teardown versus mmu_notifier release race: clear
the CD and invalidate ATS before unlinking master_domain, use a no-account
CD write in arm_smmu_mm_release(), and re-clear the CD after unlinking.
It also avoids propagating attach_dev() failures from the last-PASID
downgrade path, as required by the IOMMU core.
[1] https://lore.kernel.org/linux-iommu/DU0PR04MB94172CB3F138AD39E9B6DEEF887F9@DU0PR04MB9417.eurprd04.prod.outlook.com/
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
Peng Fan (9):
iommu/arm-smmu-v3: Allocate streams individually
iommu/arm-smmu-v3: Delay stream allocation to inside the mutex
iommu/arm-smmu-v3: Plumb the CD table into the CD helpers
iommu/arm-smmu-v3: Use a per-domain CD table for non-PASID streams
iommu/arm-smmu-v3: Support shared SIDs in insert/remove_master
iommu/arm-smmu-v3: Group aliasing devices into the same IOMMU group
iommu/arm-smmu-v3: Wire up shared-SID STE ordering and feature gating
iommu/arm-smmu-v3: Serialize shared-SID changes with attach
iommu/arm-smmu-v3: Quiesce PASID before mm release unlinks
.../iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 26 +-
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 11 +-
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c | 8 +-
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 739 ++++++++++++++++-----
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 27 +-
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 9 +-
6 files changed, 632 insertions(+), 188 deletions(-)
---
base-commit: aaa2f954c21b205a0bcd0961e5b2be4e82e58455
change-id: 20261112-b4-smmu-shared-sid-ver8-d6e35dddd5a9
Best regards,
--
Peng Fan <peng.fan@nxp.com>
next reply other threads:[~2026-11-13 13:22 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 13:27 Peng Fan (OSS) [this message]
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 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 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=20261113-b4-smmu-shared-sid-ver8-v8-0-587307a77f3a@nxp.com \
--to=peng.fan@oss.nxp.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=nicolinc@nvidia.com \
--cc=peng.fan@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 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®