mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH RFC v8 0/9] iommu/arm-smmu-v3: Support shared Stream IDs
@ 2026-11-13 13:27 Peng Fan (OSS)
  2026-11-13 13:27 ` [PATCH RFC v8 1/9] iommu/arm-smmu-v3: Allocate streams individually Peng Fan (OSS)
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Peng Fan (OSS) @ 2026-11-13 13:27 UTC (permalink / raw)
  To: Will Deacon, Robin Murphy, Joerg Roedel (AMD),
	Jean-Philippe Brucker, Nicolin Chen, Jason Gunthorpe,
	Thierry Reding, Krishna Reddy, Jonathan Hunter, Jason Gunthorpe
  Cc: linux-arm-kernel, iommu, linux-kernel, linux-tegra, Peng Fan

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>


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-11-13 13:23 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 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)

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®