Linux Documentation
 help / color / mirror / Atom feed
* [PATCH v4 00/27] vfio/pci: Add CXL Type-2 device passthrough support
@ 2026-08-13  9:36 mhonap
  2026-08-13  9:36 ` [PATCH v4 01/27] cxl: Fix resource.c include path and export cxl_restore_hdm_after_pci_reset mhonap
                   ` (26 more replies)
  0 siblings, 27 replies; 28+ messages in thread
From: mhonap @ 2026-08-13  9:36 UTC (permalink / raw)
  To: alex, jgg, ankita, jic23, dave.jiang, alejandro.lucero-palau,
	smadhavan, corbet, skhan, dave, alison.schofield, vishal.l.verma,
	iweiny, ming.li, yishaih, skolothumtho, kevin.tian, bhelgaas,
	dmatlack, kees, gustavoars
  Cc: cjia, kjaju, vsethi, zhiw, mhonap, linux-doc, linux-kernel, kvm,
	linux-cxl, linux-pci, linux-kselftest, linux-hardening

From: Manish Honap <mhonap@nvidia.com>

This series adds VFIO passthrough for CXL Type-2 accelerators. The guest
drives its own virtual HDM decoder and can reset the device. The host
owns the physical decoder and the host physical address the memory
lands at. The guest only picks a guest physical address. This series is targeted
towards a single, non-interleaved endpoint decoder.


Base and dependencies
---------------------

  Base: Linux Stable 7.2-rc6, plus the two dependencies below

  Depends-on:
    - cxl_set_capacity() and include/cxl/pci.h from Alejandro's
      "Type2 device basic support" v30 [1]
    - CXL reset core from Srirangan's cxl_reset series (v10) [2],
      which caches the decoder programming in pdev->hdm and keeps the HDM
      decoder and reset helpers in drivers/cxl/core/resource.c. Part 1 adds
      a function-scoped reset entry (cxl_reset_dvsec_sequence) on top, and
      Part 4 builds on it.


Changes since v3
----------------

v3 [3] kept the register virtualization in cxl-core, behind an opaque
cxl_passthrough handle that exported four helpers, with vfio-pci as a thin
transport. v4 turns that around. The register emulation lives in vfio-cxl, a
separate module vfio-pci-core loads on demand, and cxl-core keeps only the
reset entry and a few enabling helpers. The patch count grew from 11 to 27,
most of it the reset handling v3 left out of scope.


Reviewer feedback addressed
---------------------------

The v3 [3] thread has the full discussion; this is where each objection landed.

Dan Williams
  - Register emulation moved from cxl-core into vfio-cxl; the opaque
    cxl_passthrough handle and drivers/cxl/core/passthrough.c are gone.
  - The lock-on-commit FSM is fixed: a committed and locked decoder ignores
    further control writes until a reset, and the commit bit is not cleared
    while locked.
  - HDM mmap handles huge pages; the fault handler inserts the HPA pfn at the
    largest aligned order.
  - The BAR sub-block request is skipped through a flag on the cxl-core
    register map (a BAR-owning driver leaves the sub-blocks unclaimed), not a
    workaround on the vfio side.
  - HOST_FIRMWARE_COMMITTED is dropped; a present cap already implies a
    committed decoder, since bind fails without an active one.
  - cxl_get_hdm_info() is dropped in favour of reading pdev->hdm.
  - Style items are applied: the module lives under drivers/vfio/pci/cxl/, it
    reuses the register defines from pci_regs.h and cxl.h, and it cleans up
    with devm_add_action_or_reset().

Alex Williamson
  - vfio-pci does not statically depend on CXL; it loads vfio-cxl on demand
    and pins it per bound device.
  - The CXL state is sampled at open_device, not at bind, so a low-power
    transition cannot leave it stale.
  - The device info cap drops the region indices; regions are found by VFIO
    subtype, and the component-register geometry is on the comp-reg region
    info cap.
  - The DVSEC clip shim is replaced by a DVSEC readfn/writefn in ecap_perms
    that range-checks the offset against the stored DVSEC body.
  - vdev->cxl is a typed struct vfio_cxl_state pointer, not void *.
  - cxl_await_range_active() stays in cxl-core; vfio does not call or export
    it, and the cover no longer claims otherwise.

Dave Jiang
  - The base moved to Linux 7.2-rc6 (plus the two named dependencies), so the
    series applies cleanly with b4 (v3 failed on its stated base).

Richard Cheng
  - The host hang on real hardware is fixed. The HDM region is reached through
    an mmap fault that inserts the HPA pfn rather than a memremap(WB) kva, and
    the CXL state is acquired at open rather than at bind.


Patch order
-----------

The patches are ordered so the tree builds at every commit and each
change sits next to the code it depends on. Six groups:

  Part 1  CXL core (patches 1-5)
    - Register-map plumbing so a BAR-owning driver can leave the HDM/RAS
      sub-blocks unclaimed.
    - Component register defines moved to include/uapi/cxl/cxl_regs.h so a VMM
      can consume them.
    - Media readiness established in cxl_mem_probe() so a mailbox-less Type-2
      memdev created through devm_cxl_probe_mem() is not rejected.
    - A function-scoped reset entry for vfio-pci.

  Part 2  VFIO-CXL bring-up (patches 6-13)
    - The vfio-cxl module and its ops-provider hook into vfio-pci-core.
    - The CXL memory device created at bind.
    - A bind-time gate that rejects decoder topologies the emulation does not
      model.
    - Ownership of the whole component BAR.
    - A vfio-pci-core helper for a provider to exclude a BAR sub-range from
      mmap, read/write, and DMA-BUF export.

  Part 3  HDM region and register regions (patches 14-21)
    - The CXL region type, the open/close hooks, the DVSEC shadow and its
      virtualization.
    - The HDM region as an mmap-able region mapped write-back cacheable
      (CXL.mem is coherent) together with the trapped HDM decoder register
      snapshot.
    - The decoder block is kept off the direct BAR mapping.
    - Lock-on-commit decoder emulation, and the UAPI that describes a CXL device
      to userspace.
    - DVSEC virtualization and decoder emulation apply the CXL r4.0 write
      class field by field:
        - Control is programmable
        - Status is write-1-to-clear
        - Capability, Lock and the Range/Base/Size fields keep their firmware
          snapshot or their commit-gated state.
    - The CXL.mem-enable bit in the DVSEC control register is pinned on.
    - A guest store to the decoded window with CXL.mem disabled would fault the
      device and raise a host SError, so a guest request to clear the bit is
      ignored.

  Part 4  VFIO-CXL reset (patches 22-24)
    - HDM mapping revoke across reset and power transitions
    - Decoder snapshot refresh after reset
    - A guest-triggered CXL reset driven from the DVSEC.

  Part 5  CXL opt-out (patch 25)
    - A vfio_pci.disable_cxl module parameter and a per-device
      vdev->disable_cxl bit a variant driver sets in its own .init before
      it calls vfio_pci_core_init_dev().
    - Setting it later, in probe, is too late: the core .init has already
      attached the CXL provider. An admin or a variant driver can keep the CXL
      extensions out of the path and drive the device as plain vfio-pci.
    - Mirrors the disable_denylist opt-out.

  Part 6  Documentation and selftests (patches 26-27)


Subsystem boundary
------------------

vfio-pci-core does not implement CXL registers. vfio-cxl is a separate
module that registers a struct vfio_cxl_ops at init. vfio-pci-core loads
it on demand for a CXL device (request_module plus pcie_is_cxl) and pins
it per bound device. If a modular provider is missing or fails to load,
the device is driven as plain vfio-pci. The bind only defers for the
built-in initcall-order case, where request_module cannot help.

The core exposes only the primitives that have to live in core
(memory_lock, mapping revoke, dma-buf quiesce, and the BAR sub-range
exclusion). CXL-specific work stays behind the ops.


Memory ownership
----------------

The host resolves the host physical address once, at bind, through
devm_cxl_probe_mem(). The memdev is owned for the bind lifetime and torn
down at unbind. The HPA range is claimed IORESOURCE_EXCLUSIVE so no
mismatched cacheable alias can form, including one mapped through
/dev/mem.

The guest programs a guest physical address into a trapped virtual
decoder and polls a shadow for commit. It never reaches the physical
decoder registers. Those are served only through the trap and are
excluded from the direct BAR mapping, so the guest cannot move the host
physical window.


HDM region access
-----------------

The HDM region carries the coherent device memory. A VMM mmaps it and
maps it into the guest through stage-2; that is the access path. The
region advertises READ and WRITE so a VMM can derive an accessible (non
PROT_NONE) mmap protection from those flags, but fd read/write on the
region is rejected with -EIO.

The guest-facing mmap fault maps the pfn directly and does not hit that path.
The flags describe the mmap protection; they are not a promise of fd I/O.

The fault path only inserts the pfn while the decoder is in a known-good
restored state and the device has PCI Memory-Space enabled, so a host
access cannot reach a revoked or disabled decoder.


Reset
-----

A CXL Type-2 device is reset through its DVSEC sequence at every path
that can reset it, not through an FLR. A guest write of
Initiate_CXL_Reset in the CXL DVSEC is trapped, not forwarded. Under
memory_lock, with the HDM mapping revoked and the IOMMU mapping already
blocked, the host saves config, drops Bus Master, runs
cxl_reset_dvsec_sequence(), and restores config with Bus Master still
dropped until the outcome is known. Bus Master is re-enabled only after
a clean reset, so the function cannot DMA over decoders that were not
restored. The guest owns Mem_Clr_Enable. The outcome comes back through
DVSEC STATUS2 for the guest to poll.

The same DVSEC reset is the primary reset method at every vfio-pci-core
site. VM power-on (enable), power-off (close), the VFIO_DEVICE_RESET
ioctl, and a guest FLR emulated through config space all go through a
shared helper.

A bus hot reset rejects a multifunction CXL device. A single-function
one is quiesced through its DVSEC sequence before the secondary bus
reset. Every path revokes the HDM mapping first. The secondary bus reset
clears the physical decoder, so the decoder is restored and the snapshot
is re-sampled afterward, with Bus Master held dropped across the restore
so nothing can DMA over cleared decode. A restore failure is reported
through the reset ioctl; the bus reset's success is not returned in that
case.

A bound CXL Type-2 device is also kept out of idle D3. It is NoSoftRst-,
so a D3hot->D0 transition soft-resets the function and clears the
accelerator memory controller. That can corrupt the coherent CXL.mem the
decoder exposes, and only the accelerator's own driver re-initializes
it. vfio-cxl sets disable_idle_d3 so the host keeps the device in D0
while it is bound, rather than powering it down between opens.


Validation
----------

  - Each patch builds (drivers/cxl and drivers/vfio) and passes
    scripts/checkpatch.pl --codespell --strict with no errors, warnings, or
    checks.
  - The series applies in sequence on the stated base on top of stated
    dependencies.
  - Ran couple of rounds of masoncl/review-prompts on this series before posting.
  - Testing workaround (not part of this series):
     - The HDM region is a VM_PFNMAP RAM-device region, and mapping it into a
       guest IOMMU address space for device-side ATS currently returns
       -EOPNOTSUPP. The in-tree iommufd/VFIO map path does not follow a
       VM_PFNMAP range, so a DMA map of the CXL.mem range is refused (QEMU logs
       it as a non-fatal vfio_container_dma_map ... = -95 warning and continues).
     - To exercise the ATS path on hardware, an out-of-tree workaround that
       bypasses the PFNMAP restriction on the iommufd map path was applied so
       the CXL.mem range could be mapped into the stage-2 IOAS.
     - The selftests and the CPU/coherent guest access paths do not need it;
       only device-side ATS to CXL.mem does.
     - The intended upstream fix is a dma-buf based import of the CXL.mem range
       into iommufd. That will be a separate series.


Follow-on UAPI
--------------

- The trapped component-register region spans the whole HDM decoder block, not
  just decoder 0, so a multi-decoder device needs no new region or cap: a VMM
  reads the decoder count and each committed base from the block itself.
- The COMP_REGS geometry cap keeps a reserved field as a versioning anchor.
- Further trapped surfaces such as CXL RAS are planned as new CXL region
  subtypes (3+) rather than by extending this cap.
- The single committed, non-interleaved decoder is a bind-time policy in one
  place, not an ABI assumption, so in future multi-decoder and switched
  topologies relax only at that place.


Deferred
--------

  - Topology reach. Switched, multi-decoder, and interleaved decoders
    stay rejected at bind.
  - Non Firmware committed decoder system support.


References
----------

[1] [PATCH v30 0/2] Type2 device basic support
https://lore.kernel.org/all/20260629183727.51502-1-alejandro.lucero-palau@amd.com/

[2] [PATCH v10 00/12] PCI/CXL: Add CXL reset support for Type 2 devices
https://lore.kernel.org/linux-cxl/20260804192958.1823952-1-smadhavan@nvidia.com/

[3] Previous version of this patch series
[PATCH v3 00/11] vfio/pci: Add CXL Type-2 device passthrough support
https://lore.kernel.org/linux-cxl/20260625165407.1769572-1-mhonap@nvidia.com/


Manish Honap (27):
  cxl: Fix resource.c include path and export cxl_restore_hdm_after_pci_reset
  cxl/regs: Skip sub-block region request for BAR-owning drivers
  cxl: Move component register defines to uapi/cxl/cxl_regs.h
  cxl: Establish media readiness in cxl_mem_probe()
  cxl: Add a function-scoped reset entry for vfio-pci
  vfio/pci: Add CXL ops registration interface
  vfio/pci: Detect CXL devices and load vfio-cxl on demand
  vfio/cxl: Add the vfio-cxl module skeleton
  vfio/cxl: Create the CXL memory device at bind
  vfio/cxl: Reject unsupported decoder topologies at bind
  vfio/cxl: Own the whole component register BAR
  vfio/pci: Let a provider exclude a BAR sub-range from mmap
  vfio/pci: Refuse read/write to an excluded BAR sub-range
  vfio: Add CXL region type for the HDM region
  vfio/pci: Call CXL open and close hooks around device use
  vfio/cxl: Shadow the CXL DVSEC body at open
  vfio/cxl: Virtualize the CXL DVSEC
  vfio/cxl: Expose the HDM memory and trap the decoder registers
  vfio/cxl: Keep the HDM decoder block off the direct BAR mapping
  vfio/cxl: Emulate the HDM decoder commit handshake
  vfio/cxl: Describe the CXL device and decoder geometry to userspace
  vfio/cxl: Revoke the HDM mapping on reset and power transitions
  vfio/cxl: Refresh the decoder snapshot after a device reset
  vfio/cxl: Service a guest-triggered CXL reset
  vfio/pci: Provide an opt-out for the CXL Type-2 extensions
  Documentation: vfio-pci: Document CXL Type-2 device passthrough
  selftests/vfio: Add CXL Type-2 passthrough corner-case tests

 Documentation/driver-api/index.rst            |    1 +
 Documentation/driver-api/vfio-pci-cxl.rst     |  141 +++
 MAINTAINERS                                   |   10 +
 drivers/cxl/core/pci.c                        |   24 +-
 drivers/cxl/core/regs.c                       |   32 +-
 drivers/cxl/core/resource.c                   |   72 +-
 drivers/cxl/cxl.h                             |   47 +-
 drivers/cxl/mem.c                             |    9 +-
 drivers/cxl/pci.c                             |    4 +-
 drivers/vfio/pci/Kconfig                      |    2 +
 drivers/vfio/pci/Makefile                     |    2 +
 drivers/vfio/pci/cxl/Kconfig                  |   11 +
 drivers/vfio/pci/cxl/Makefile                 |    3 +
 drivers/vfio/pci/cxl/vfio_cxl_core.c          | 1036 +++++++++++++++++
 drivers/vfio/pci/vfio_pci.c                   |    9 +
 drivers/vfio/pci/vfio_pci_config.c            |   42 +-
 drivers/vfio/pci/vfio_pci_core.c              |  478 +++++++-
 drivers/vfio/pci/vfio_pci_dmabuf.c            |   13 +
 drivers/vfio/pci/vfio_pci_priv.h              |   35 +
 drivers/vfio/pci/vfio_pci_rdwr.c              |    8 +
 include/cxl/cxl.h                             |   15 +
 include/cxl/pci.h                             |    2 +-
 include/linux/vfio_pci_core.h                 |   37 +
 include/uapi/cxl/cxl_regs.h                   |   58 +
 include/uapi/linux/pci_regs.h                 |    1 +
 include/uapi/linux/vfio.h                     |   26 +
 tools/testing/selftests/vfio/Makefile         |    1 +
 .../selftests/vfio/lib/vfio_pci_device.c      |   57 +-
 .../selftests/vfio/vfio_cxl_type2_test.c      |  799 +++++++++++++
 29 files changed, 2877 insertions(+), 98 deletions(-)
 create mode 100644 Documentation/driver-api/vfio-pci-cxl.rst
 create mode 100644 drivers/vfio/pci/cxl/Kconfig
 create mode 100644 drivers/vfio/pci/cxl/Makefile
 create mode 100644 drivers/vfio/pci/cxl/vfio_cxl_core.c
 create mode 100644 include/uapi/cxl/cxl_regs.h
 create mode 100644 tools/testing/selftests/vfio/vfio_cxl_type2_test.c


base-commit: 075b74841bd0065a3bda3440873c747938e69b68
-- 
2.25.1


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

end of thread, other threads:[~2026-08-13  9:42 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-13  9:36 [PATCH v4 00/27] vfio/pci: Add CXL Type-2 device passthrough support mhonap
2026-08-13  9:36 ` [PATCH v4 01/27] cxl: Fix resource.c include path and export cxl_restore_hdm_after_pci_reset mhonap
2026-08-13  9:36 ` [PATCH v4 02/27] cxl/regs: Skip sub-block region request for BAR-owning drivers mhonap
2026-08-13  9:36 ` [PATCH v4 03/27] cxl: Move component register defines to uapi/cxl/cxl_regs.h mhonap
2026-08-13  9:36 ` [PATCH v4 04/27] cxl: Establish media readiness in cxl_mem_probe() mhonap
2026-08-13  9:36 ` [PATCH v4 05/27] cxl: Add a function-scoped reset entry for vfio-pci mhonap
2026-08-13  9:36 ` [PATCH v4 06/27] vfio/pci: Add CXL ops registration interface mhonap
2026-08-13  9:36 ` [PATCH v4 07/27] vfio/pci: Detect CXL devices and load vfio-cxl on demand mhonap
2026-08-13  9:36 ` [PATCH v4 08/27] vfio/cxl: Add the vfio-cxl module skeleton mhonap
2026-08-13  9:36 ` [PATCH v4 09/27] vfio/cxl: Create the CXL memory device at bind mhonap
2026-08-13  9:36 ` [PATCH v4 10/27] vfio/cxl: Reject unsupported decoder topologies " mhonap
2026-08-13  9:36 ` [PATCH v4 11/27] vfio/cxl: Own the whole component register BAR mhonap
2026-08-13  9:36 ` [PATCH v4 12/27] vfio/pci: Let a provider exclude a BAR sub-range from mmap mhonap
2026-08-13  9:36 ` [PATCH v4 13/27] vfio/pci: Refuse read/write to an excluded BAR sub-range mhonap
2026-08-13  9:36 ` [PATCH v4 14/27] vfio: Add CXL region type for the HDM region mhonap
2026-08-13  9:36 ` [PATCH v4 15/27] vfio/pci: Call CXL open and close hooks around device use mhonap
2026-08-13  9:36 ` [PATCH v4 16/27] vfio/cxl: Shadow the CXL DVSEC body at open mhonap
2026-08-13  9:36 ` [PATCH v4 17/27] vfio/cxl: Virtualize the CXL DVSEC mhonap
2026-08-13  9:36 ` [PATCH v4 18/27] vfio/cxl: Expose the HDM memory and trap the decoder registers mhonap
2026-08-13  9:36 ` [PATCH v4 19/27] vfio/cxl: Keep the HDM decoder block off the direct BAR mapping mhonap
2026-08-13  9:36 ` [PATCH v4 20/27] vfio/cxl: Emulate the HDM decoder commit handshake mhonap
2026-08-13  9:36 ` [PATCH v4 21/27] vfio/cxl: Describe the CXL device and decoder geometry to userspace mhonap
2026-08-13  9:36 ` [PATCH v4 22/27] vfio/cxl: Revoke the HDM mapping on reset and power transitions mhonap
2026-08-13  9:36 ` [PATCH v4 23/27] vfio/cxl: Refresh the decoder snapshot after a device reset mhonap
2026-08-13  9:36 ` [PATCH v4 24/27] vfio/cxl: Service a guest-triggered CXL reset mhonap
2026-08-13  9:36 ` [PATCH v4 25/27] vfio/pci: Provide an opt-out for the CXL Type-2 extensions mhonap
2026-08-13  9:36 ` [PATCH v4 26/27] Documentation: vfio-pci: Document CXL Type-2 device passthrough mhonap
2026-08-13  9:36 ` [PATCH v4 27/27] selftests/vfio: Add CXL Type-2 passthrough corner-case tests mhonap

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox