[RFC PATCH 0/1] iommu/riscv: mark endpoint ATS-broken on ATS invalidation timeout

bingyu.xian shanbeeyoo at gmail.com
Thu Jun 25 02:34:15 PDT 2026


From: Bingyu Shan <shanbeeyoo at gmail.com>

This RFC proposes handling ATS invalidation timeout in the RISC-V IOMMU
driver, following the class of problem ARM SMMUv3 recently addressed as
"ATC invalidation timeout / quarantine": a PCIe endpoint that fails to
complete an ATS invalidation keeps stale ATC entries and can keep DMA-ing
through them.

The RISC-V IOMMU driver currently has no such handling.
riscv_iommu_cmd_sync() only logs "Hardware error: command execution
timeout" once and discards the failure, with no attribution to a device
and no policy response.

Patch 1 adds the first, conservative milestone:

  * On a command-queue timeout, read CQH to find the offending command; if
    it is an ATS.INVAL, extract its device-id (the RISC-V analog of ARM
    SMMUv3 CERROR_ATC_INV_IDX) and schedule deferred marking.

  * The marking worker sets a per-device ats_broken flag, increments a
    counter, calls pci_disable_ats(), and logs. Deferred to a work item
    because cmd_sync() may run with only RCU held while the device lookup
    takes a sleeping mutex.

  * riscv_iommu_enable_pdev() refuses pci_enable_ats() for an ats_broken
    device, so a broken endpoint is not put back on the ATS path.

  * Device tracking (the DID-keyed rbtree) is moved from the PRI-only path
    to probe_device/release_device, so ATS-only devices are tracked and can
    be attributed. This also fixes dev_to_iommu() not being usable inside
    probe_device() (the iommu core only links dev->iommu after probe
    returns), and a latent duplicate-devid double-unlock in the rbtree
    insert.

  * Debugfs fault injection (inject_ats_inval_timeout) and a state table
    (ats_devices) so the marking path can be exercised. Real RISC-V IOMMU
    hardware and unmodified QEMU complete ATS.INVAL synchronously, so a
    native timeout cannot be reproduced against a real endpoint; the knob
    schedules the same worker the real cmd_sync() timeout path would.

Full quarantine and PCI reset recovery are intentionally left out of this
step; this RFC is to discuss the timeout-handling policy.

Base / dependency
-----------------

This RFC is based on Tomasz Jeznach's riscv_iommu.next branch, because the
RISC-V IOMMU ATS support series (ATS / PRI / SVA) is not yet in the IOMMU
tree. It is intended to discuss design, not for immediate merge.

  Base:  tjeznach/riscv_iommu.next  (Linux 6.15 + RISC-V ATS/PRI/SVA)
  Not based on: iommu/linux.git next (no RISC-V ATS support yet)

Open question for the list: should the ATS invalidation timeout handling
be folded into the ATS support series itself, since an ATS implementation
that does not handle timeouts is arguably incomplete?

Validation environment
----------------------

  QEMU:             qemu-system-riscv64 10.0.0 (hw/riscv unmodified, stock)
  Kernel base:      tjeznach/riscv_iommu.next + this patch
  Cross compiler:   riscv64-linux-gnu-gcc 11.4.0
  Kconfig:          RISCV_IOMMU=y, RISCV_IOMMU_PCI=y, PCI_ATS/PASID/PRI=y,
                    VIRTIO_NET=y, VIRTIO_PCI=y, DEBUG_FS=y
  Endpoint:         stock -device virtio-net-pci,ats=on (BDF 0000:00:03.0,
                    IOMMU device-id 0x18 = PCI requester id dev<<3|func)
  Boot cmdline:     root=/dev/ram rw console=ttyS0 earlycon=sbi \
                    iommu.strict=1 fw_devlink=off

  fw_devlink=off works around a platform-IOMMU deferred-probe on this QEMU
  setup ("deferred probe pending: ... /cpus/cpu at 0"). No QEMU patches are
  used; the ATS endpoint and the IOMMU are stock.

Validation log
--------------

Boot is clean (no panic). The IOMMU probes and manages the endpoint:

  [    0.442968] riscv,iommu 3010000.iommu: using wire-signaled interrupts
  [    0.448530] pci 0000:00:00.0: Adding to iommu group 0
  [    0.448908] pci 0000:00:03.0: Adding to iommu group 1
  [    0.538245] virtio-pci 0000:00:03.0: enabling device (0000 -> 0003)

ats_devices before the trigger (both RC and virtio tracked via the rbtree
populated at probe):

  devid device ats_broken ats_inval_timeouts
  0x0  0000:00:00.0  0  0
  0x18 0000:00:03.0  0  0

Inject an ATS.INVAL timeout for the virtio endpoint (DID 0x18) via the
debugfs knob, which schedules the same worker the real cmd_sync() timeout
path would:

  Injecting ATS.INVAL timeout for devid 0x18 (24) (BDF 0000:00:03.0)
  [    6.910242] virtio-pci 0000:00:03.0: marked ATS-broken after ATS.INVAL timeout

ats_devices after the trigger:

  devid device ats_broken ats_inval_timeouts
  0x0  0000:00:00.0  0  0
  0x18 0000:00:03.0  1  1

This confirms, on the real ATS path and with unmodified QEMU:

  ATS.INVAL timeout -> DID 0x18 -> 0000:00:03.0 marked ATS-broken
  (ats_broken=1, ats_inval_timeouts=1)

Caveats
-------

  * The real cmd_sync() CQH->DID path is implemented but cannot be
    triggered on unmodified QEMU (synchronous ATS.INVAL completion); the
    debugfs knob schedules the same worker to validate the marking logic.
    It would fire on real hardware or on a QEMU modelled to stall ATS.INVAL.

  * pci_disable_ats() inside the worker was a no-op in this run: ATS was
    not auto-enabled at boot (no "ats" sysfs attribute), so
    info->ats_enabled was false. The disable and the ATS-enable guard are
    correct by inspection but not dynamically triggered here.

  * Stale-ATC data corruption (device keeps an old IOVA->PA mapping and
    DMAs through it after a missed invalidation) is out of scope; that
    needs an endpoint with a real device-side ATC, which stock virtio-pci
    does not model.

Todo / open questions
---------------------

  * Should this be split (rbtree tracking / timeout marking / debugfs) for
    a non-RFC version?
  * Quarantine vs. just "mark and refuse re-enable": what policy does the
    list want?
  * PCI reset recovery semantics.
  * Re-base onto iommu/linux.git next once the ATS support series lands.

Bingyu Shan (1):
  iommu/riscv: RFC: mark endpoint ATS-broken on ATS invalidation timeout

 drivers/iommu/riscv/iommu.c | 210 ++++++++++++++++++++++++++++++++++--
 drivers/iommu/riscv/iommu.h |   9 ++
 2 files changed, 210 insertions(+), 9 deletions(-)

--
2.54.0




More information about the linux-riscv mailing list