Skip to content

Per-device CFMWS base for multi-GPU CXL passthrough - #28

Closed
mmhonap wants to merge 88 commits into
NVIDIA:nvidia_unstable-11.0from
mmhonap:fmws_fix
Closed

Per-device CFMWS base for multi-GPU CXL passthrough#28
mmhonap wants to merge 88 commits into
NVIDIA:nvidia_unstable-11.0from
mmhonap:fmws_fix

Conversation

@mmhonap

@mmhonap mmhonap commented Jul 9, 2026

Copy link
Copy Markdown

This series fixes multi-GPU CXL Type-2 passthrough on the ARM virt machine,
where each GPU sits behind its own pxb-cxl with its own single-target CXL
fixed memory window (CFMWS).

The branch carried an interim model that used a single global CFMWS window:
setup_locked_hdm() programmed every firmware-committed VFIO-CXL device's HDM
decoder 0 at the first placed window base, and a second device was rejected
outright. With more than one GPU every device therefore landed at window 0's
base, all guest endpoint decoders reported the same HPA, and only the first
CXL region attached; the other GPU drivers failed to initialize.

The fix programs each device's HDM decoder 0 at the base of the CFMWS that
targets its own host bridge (pci_device_root_bus()->parent_dev), so an
N-device / N-window layout places each device in its own window. Selection is
by topology and fails closed: only a unique single-target CFMWS is accepted,
and an invalid topology aborts startup rather than booting a half-configured
device.

The series first removes the single-window stopgap (three reverts), then adds
per-device selection, then drops the globals the stopgap left unused:

1-2 Revert the FMWS reservation and duplicate-user rejection. Both exist
only to guard the single global window.
3 Revert the vfio/pci.c part of "Tighten FMWS placement" (the
reject-second-device flag). The rest of that commit (fw->placed
tracking, CEDT/MMIO handling, ARM highmem ordering) is unrelated and
kept.
4 Program HDM decoder 0 with the per-device CFMWS base, and reject
hot-add of a VFIO-CXL device (the machine_done notifier exit()s on
error, which would kill a running guest).
5 Drop cxl_fmws_base / cxl_fmws_size / cxl_fmws_count, now unused.

Ported from nvidia_unstable-10.1. Two branch differences were handled: the
DPA region is mapped with memory_region_add_subregion_overlap() because on
this branch the CFMWS window is mapped into system memory at fw->base, and
the embedded PCIDevice is reached via PCI_DEVICE(vdev) (the field is
parent_obj here, not pdev).

Testing: built for aarch64-softmmu. Verified with up to four GPUs passed
through, each on its own single-target CFMWS. Each endpoint lands in its own
window with a distinct base and all guest GPU drivers initialize:

/sys/bus/cxl/devices/decoder5.0/start = 0x80000000000
/sys/bus/cxl/devices/decoder6.0/start = 0x84000000000
/sys/bus/cxl/devices/decoder7.0/start = 0x88000000000
/sys/bus/cxl/devices/decoder8.0/start = 0x8c000000000

Limitation: only a direct topology is handled (one endpoint per pxb-cxl, no
CXL switch in the path). An endpoint behind a switch is not yet detected or
rejected.

NathanChenNVIDIA and others added 30 commits May 27, 2026 18:16
…ameters

Introduce smmuv3_accel_auto_finalise() to resolve properties that are
set to 'auto' for accelerated SMMUv3. This helper function allows
properties such as ats, ril, ssidsize, and oas support to be resolved
from host IOMMU capabilities via IOMMU_GET_HW_INFO.

The later commits in this series set the auto_mode flag to true when
an accel SMMUv3 property value is explicitly set to 'auto', or if the
property value is not set and defaults to auto mode.

Setting these property values to 'auto' requires at least one
cold-plugged device to retrieve and finalise these properties. If the
auto_mode flag is true, register a machine_init_done notifier to
verify this requirement and fail boot if it is not met.

Hot-plugged devices into an accel SMMUv3-associated bus will re-use
the resolved host values from the initial cold-plug.

Subsequent patches will make use of this helper to resolve 'auto' to
what is reported by host IOMMU capabilities.

Suggested-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
(backported from https://lore.kernel.org/all/20260512193520.3109172-1-nathanc@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Allow accelerated SMMUv3 Address Translation Services support property
to be derived from host IOMMU capabilities. Derive host values using
IOMMU_GET_HW_INFO, retrieving ATS capability from IDR0.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
(backported from https://lore.kernel.org/all/20260512193520.3109172-1-nathanc@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Allow accelerated SMMUv3 Range Invalidation support property to be
derived from host IOMMU capabilities. Derive host values using
IOMMU_GET_HW_INFO, retrieving RIL capability from IDR3.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
(backported from https://lore.kernel.org/all/20260512193520.3109172-1-nathanc@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…ize"

Allow accelerated SMMUv3 SSID size property to be derived from host
IOMMU capabilities. Derive host values using IOMMU_GET_HW_INFO,
retrieving SSID size from IDR1. When the auto SSID size is resolved
to a non-zero value, PASID capability is advertised to the vIOMMU
and accelerated use cases such as Shared Virtual Addressing (SVA)
are supported.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
(backported from https://lore.kernel.org/all/20260512193520.3109172-1-nathanc@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Allow accelerated SMMUv3 OAS property to be derived from host IOMMU
capabilities. Derive host values using IOMMU_GET_HW_INFO, retrieving
OAS from IDR5.

This keeps the OAS value advertised by the virtual SMMU compatible with
the capabilities of the host SMMUv3, so that the intermediate physical
addresses (IPA) consumed by host SMMU for stage-2 translation do not
exceed the host's max supported IPA size.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
(backported from https://lore.kernel.org/all/20260512193520.3109172-1-nathanc@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…auto

Set the default value of ATS, RIL, SSIDSIZE, and OAS to auto, in order
to match the host IOMMU properties when accel=on.

If accel=off and these property values are set to auto, the default
property values defined in smmuv3_init_id_regs() for OAS and RIL will
remain unchanged, while SSIDSIZE and ATS values will remain initialized
at 0.

Introduce a new compat for the changed defaults.

Signed-off-by: Nathan Chen <nathanc@nvidia.com>
(backported from https://lore.kernel.org/all/20260512193520.3109172-1-nathanc@nvidia.com/)
[jan: manually apply machine.c changes — hw_compat_11_0 array does not exist on v11.0.0 base; added array, include, and boards.h declaration]
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…rties

Update documentation now that "auto" is supported for accelerated SMMUv3
properties.

Signed-off-by: Nathan Chen <nathanc@nvidia.com>
(backported from https://lore.kernel.org/all/20260512193520.3109172-1-nathanc@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
By turning the inline functions into stubs we can avoid the
use of target-specific CONFIG_DEVICES include in a hw/ header,
allowing to build the source files including it as common objects.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Shameer Kolothum <skolothumtho@nvidia.com>
Message-Id: <20260410200031.18572-3-philmd@linaro.org>
(cherry picked from commit 12ce4d9630ae09edec706f6254417e3ec96e08e5)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
We used idev and idevc naming for HostIOMMUDeviceIOMMUFD and corresponding
class variables which followed the iommufd_device naming in linux kernel.

This is mixed with the hiod naming for base type HostIOMMUDevice. Rename
HostIOMMUDeviceIOMMUFD* to hiodi* for consistency in QEMU.

No functional change intended.

Suggested-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260401080354.1347212-1-zhenzhong.duan@intel.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
(cherry picked from commit e2b7310276087351fadd6afbe9e5a3fff9c25f8d)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
The updated IOMMUFD uAPI introduces the ability for userspace to request
a specific hardware info data type via IOMMU_GET_HW_INFO. Update
iommufd_backend_get_device_info() to set IOMMU_HW_INFO_FLAG_INPUT_TYPE
when a non-zero type is supplied, and adjust all callers to pass a type
value explicitly initialised to zero (IOMMU_HW_INFO_TYPE_DEFAULT) when
no specific type is requested.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…to allow user ptr

The updated IOMMUFD VIOMMU_ALLOC uAPI allows userspace to provide a data
buffer when creating a vIOMMU (e.g. for Tegra241 CMDQV). Extend
iommufd_backend_alloc_viommu() to pass a user pointer and size to the
kernel.

Update the caller accordingly.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…ueue

Add a helper to allocate an iommufd backed HW queue for a vIOMMU.

While at it, define a struct IOMMUFDHWqueue for use by vendor
implementations.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Add a backend helper to mmap hardware MMIO regions exposed via iommufd for
a vIOMMU instance. This allows user space to access HW-accelerated MMIO
pages provided by the vIOMMU.

The caller is responsible for unmapping the returned region.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…UFDVeventq

The viommu field is assigned but never used. Callers freeing the
veventq already have access to the IOMMUFDViommu object through other
references, so this field is redundant.

Removing it also simplifies upcoming changes where veventq is
allocated based on the viommu id before the IOMMUFDViommu object is
created (e.g. vendor CMDQV-based veventq allocation).

No functional change.

Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Command Queue Virtualization (CMDQV) is a hardware extension available
on certain platforms that allows the SMMUv3 command queue to be
virtualized and passed through to a VM, improving performance.

For example, NVIDIA Tegra241 implements CMDQV to support virtualization
of multiple command queues (VCMDQs).

The term CMDQV is used here generically to refer to any platform that
provides hardware support to virtualize the SMMUv3 command queue.

CMDQV support is a specialization of the IOMMUFD-backed accelerated
SMMUv3 path. Introduce an ops interface to factor out CMDQV-specific
probe, initialization, and vIOMMU allocation logic from the base
implementation. The ops pointer and associated state are stored in
the accelerated SMMUv3 state.

This provides an extensible design to support future vendor-specific
CMDQV implementations.

No functional change.

Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…stub

Introduce a Tegra241 CMDQV backend that plugs into the SMMUv3 accelerated
CMDQV ops interface.

This patch wires up the Tegra241 CMDQV backend and provides a stub
implementation for CMDQV probe, initialization, vIOMMU allocation
and reset handling.

Functional CMDQV support is added in follow-up patches.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
[jan: Dropped unrelated FSL_IMX8MM/FSL_IMX8MM_EVK Kconfig entries from the patche context and kept only the TEGRA241_CMDQV block.]
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Add support for selecting and initializing a CMDQV backend based on the
cmdqv OnOffAuto property.

If set to OFF, CMDQV is not used and the default IOMMUFD-backed allocation
path is taken.

If set to AUTO, QEMU attempts to probe a CMDQV backend during device setup.
If probing succeeds, the selected ops are stored in the accelerated SMMUv3
state and used. If probing fails, QEMU silently falls back to the default
path.

If set to ON, QEMU requires CMDQV support. Probing is performed during
setup and failure results in an error.

When a CMDQV backend is active, its callbacks are used for vIOMMU
allocation, free, and reset handling. Otherwise, the base implementation
is used.

The current implementation wires up the Tegra241 CMDQV backend through the
generic ops interface. Functional CMDQV behaviour is added in subsequent
patches.

No functional change.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Introduce a GPtrArray in VirtMachineState to track all SMMUv3 devices
created on the virt machine, and use it when building the IORT table
instead of relying on object_child_foreach_recursive() walks of the
object tree.

This avoids recursive object traversal and provides a foundation for
subsequent patches that need direct access to SMMUv3 instances for
CMDQV-related handling.

No functional change. No bios-tables qtest failures observed.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Use IOMMU_GET_HW_INFO to query host support for Tegra241 CMDQV.

Validate the returned data type, version, and minimum number of vCMDQs and
SIDs per Tegra241 CMDQ Virtual Interface(VI). Fail the probe if the host
does not meet these requirements.

The QEMU model supports one Virtual Interface(VI) per VM with 2 vCMDQs and
16 SIDs per VI, so the probe ensures the host implementation is compatible
with these limits.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Tegra241 CMDQV extends SMMUv3 with support for virtual command queues
(VCMDQs) exposed via a CMDQV MMIO region. The CMDQV MMIO space is split
into 64KB pages:

0x00000  (CMDQ-V Config page)
0x10000  (CMDQ-V CMDQ Page0)
0x20000  (CMDQ-V CMDQ Page1)
0x30000  (Virtual Interface Page0)
0x40000  (Virtual Interface Page1)

This patch wires up the Tegra241 CMDQV init callback and allocates
vendor-specific CMDQV state. The state pointer is stored in
SMMUv3AccelState for use by subsequent CMDQV operations.

The CMDQV MMIO region and a dedicated IRQ line are registered with the
SMMUv3 device. The MMIO read/write handlers are currently stubs and will
be implemented in later patches.

The CMDQV interrupt is edge-triggered and indicates VCMDQ or VINTF
error conditions. This patch only registers the IRQ line. Interrupt
generation and propagation to the guest will be added in a subsequent
patch.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Co-developed-by: Shameer Kolothum <skolothumtho@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
SMMUv3 devices with acceleration may enable CMDQV extensions
after device realize. In that case, additional MMIO regions and
IRQ lines may be registered but not yet mapped to the platform bus.

Ensure SMMUv3 device resources are linked to the platform bus
during machine_done().

This is safe to do unconditionally since the platform bus helpers
skip resources that are already mapped.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Replace the stub implementation with real vIOMMU allocation for
Tegra241 CMDQV.

Allocate a matching vEVENTQ together with the vIOMMU, since it is
specific to the Tegra241 CMDQV vIOMMU and used to receive CMDQV
events.

Free both objects on teardown.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Co-developed-by: Shameer Kolothum <skolothumtho@nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Tegra241 CMDQV exposes control and status registers in the CMDQ-V
Config page (offset [0x0, 0x10000)) used to configure virtual command
queue allocation and interrupt behavior.

Add read/write emulation for the CMDQ-V Config region
([CMDQV_BASE, CMDQV_CMDQ_BASE]), backed by a simple register cache.
This includes CONFIG, PARAM, STATUS, VI error and interrupt maps, CMDQ
allocation map and the VINTF0 related registers defined in the CMDQ-V
Config space. Only VINTF0 is supported; VINTF1-63 are not.

Dispatch writes on access size: Introduced writel_mmio for 4-byte and
writell_mmio for 8-byte. Reads need no split as the MMIO framework masks
the returned value to the access size.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Co-developed-by: Shameer Kolothum <skolothumtho@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Tegra241 CMDQV exposes per-VCMDQ register windows through two MMIO
apertures:

  Direct VCMDQ aperture (0x10000/0x20000): VCMDQ Page0/Page1
  VINTF logical aperture (0x30000/0x40000): VINTF0 LVCMDQ Page0/Page1

Both apertures are hardware aliases of the same underlying registers:

  Page 0 (control/status): CONS_INDX, PROD_INDX, CONFIG, STATUS,
                           GERROR, GERRORN
  Page 1 (base/DRAM):      BASE_L/H, CONS_INDX_BASE_DRAM_L/H

The direct aperture Page 0 is programmable at any time so long as
CMDQV_EN is enabled. The VINTF (logical) aperture Page 0 is
programmable only once SW has mapped a VCMDQ to a VINTF; the
"logical" view is local to that VINTF.

Add read emulation for both apertures, backed by a single per-VCMDQ
register cache. VINTF aperture reads are translated to their
equivalent direct-aperture offset and served from the same cached
state.

Once IOMMU_HW_QUEUE_ALLOC and viommu_mmap are wired up in a
subsequent patch, Page 0 reads will be served directly from the
hardware-backed mmap'd page instead of the cache. Page 1 is also a
hardware alias, but the kernel only exposes mmap for Page 0, so
Page 1 reads always trap to QEMU and are served from cache.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Co-developed-by: Shameer Kolothum <skolothumtho@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
This is the write side counterpart of the VCMDQ read emulation. Add
write handling for both the direct VCMDQ aperture and the VINTF
logical aperture using the same index decoding and VINTF-to-VCMDQ
translation logic as the read path.

VINTF aperture writes are translated to their direct-aperture
equivalent and update the same cached state. Page 1 registers
(BASE, CONS_INDX_BASE) always update the cache. Once
IOMMU_HW_QUEUE_ALLOC and viommu_mmap are wired up in a subsequent
patch, Page 0 register writes will be forwarded to the hardware-
backed mmap'd page.

Ignore VCMDQ BASE writes if the VCMDQ is already enabled.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Co-developed-by: Shameer Kolothum <skolothumtho@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
The CMDQ-V CMDQ pages provide a VM wide view of all VCMDQs, while the
VINTF pages expose a logical view local to a given VINTF. Although real
hardware may support multiple VINTFs, the kernel currently exposes a
single VINTF per VM.

The kernel provides an mmap offset for the VINTF Page0 region during
vIOMMU allocation. However, the logical-to-physical association between
VCMDQs and a VINTF is only established after HW_QUEUE allocation. Prior
to that, the mapped Page0 does not back any real VCMDQ state.

When VINTF is enabled, mmap the kernel provided Page0 region and set
ENABLE_OK only if the mmap succeeds. Unmap it when VINTF is disabled.
This prepares the VINTF mapping in advance of subsequent patches that
add VCMDQ allocation support.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Co-developed-by: Shameer Kolothum <skolothumtho@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Introduce address_space_range_is_ram(), a helper to determine whether a
guest physical address range within an AddressSpace resolves entirely
to RAM-backed MemoryRegions. The range is walked using
address_space_translate() so contiguous RAM-only ranges return true
even when they cross multiple MemoryRegion boundaries; any byte
backed by non-RAM (MMIO, ROM device, hole) returns false.

Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Add support for allocating IOMMUFD hardware queues when the guest
programs the VCMDQ BASE registers.

VCMDQ_EN lives in VCMDQ_CONFIG, which is on the VINTF Page0 region
that a later patch maps directly into the guest — so QEMU won't trap
its writes. Allocate the hardware queue instead once all of these
are set: a RAM-backed BASE, CMDQ_ALLOC_MAP.ALLOC, and CMDQV / VINTF
enabled. Each precondition write retries the allocation, so the
guest may program them in any order.

If a hardware queue was previously allocated for the same VCMDQ,
free it before reallocation.

Writes with invalid addresses are ignored.

All allocated VCMDQs are freed when CMDQV or VINTF is disabled, or
when the ALLOC bit is cleared.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Co-developed-by: Shameer Kolothum <skolothumtho@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
… backing

Introduce tegra241_cmdqv_vintf_ptr() to route VCMDQ Page0 register
accesses through the mmap'd VINTF page0 backing once a hardware
queue has been allocated.

There are two QEMU trapped MMIO apertures for VCMDQ Page0 registers:

  - Direct VCMDQ Page0 aperture (offset 0x10000)
  - VINTF Page0 (offset 0x30000)

These are hardware aliases: they address the same underlying
registers. A subsequent patch maps the VINTF aperture as a
guest-direct RAM region; in this patch both remain QEMU-trapped.

VCMDQ Page0 accesses operate in one of two mutually exclusive modes,
depending on whether a hardware queue (IOMMU_HW_QUEUE_ALLOC) has
been allocated for the VCMDQ:

  Pre-alloc:  vintf_ptr is NULL. Both apertures use QEMU's register
              cache. Hardware is not yet engaged.

  Post-alloc: vintf_ptr is valid. Both QEMU trapped apertures access
              registers directly via the mmap'd vintf_page0 pointer,
              bypassing the cache. Hardware is the single source of
              truth.

The pre-to-post-alloc transition is triggered by the IOMMUFD hardware
queue allocation. The tegra241_cmdqv_sync_vcmdq() copies any pre-alloc
cached writes (CONS_INDX, PROD_INDX, CONFIG, GERRORN) into the mmap'd
page so the guest's view survives the transition.

CMDQV acceleration only becomes active once the guest enables VINTF
and the corresponding HW QUEUE is allocated through IOMMUFD. Until
then, all VCMDQ accesses are served from the emulated register cache
with no real hardware command processing. This matches the CMDQV
hardware specification: if the logical CMDQ index does not map to any
allocated Virtual CMDQ, "the access is dropped with no Fault/Interrupt".

Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Some RAM device regions created with memory_region_init_ram_device_ptr()
are not intended to be P2P DMA targets.

The VFIO listener currently treats all RAM device regions as DMA
capable and attempts to map them into the IOMMU. For regions without
dma-buf backing this fails and prints warnings such as:

  IOMMU_IOAS_MAP failed: Bad address, PCI BAR?

Introduce a MemoryRegion flag (ram_device_skip_iommu_map) to mark RAM
device regions that should not be IOMMU mapped, paired with
memory_region_skip_iommu_map() / memory_region_set_skip_iommu_map()
accessors. When the flag is set, the VFIO listener skips DMA mapping
for that region.

Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
(backported from: https://lore.kernel.org/all/20260519103727.899332-1-skolothumtho@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Acked-by: Nathan Chen <nathanc@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
nvmochs and others added 24 commits May 29, 2026 17:06
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
The dma_map_file pathway doesn't fit into the kernel WAR that bypasses
PFNMAP, resulting dma_map failures.

Only the dma_map pathway could work. So retry with that upon a failure.

Keep this WAR until the kernel WAR for PFNMAP is lifted.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
(backported from commit faff92d https://github.com/nvmochs/QEMU/tree/stable101_smmuv3-accel-07212025_egm)
[nathanc: Moved changes from hw/vfio/container-base.c to hw/vfio/container.c for 11.0 base]
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
Acked-by: Ian May <ianm@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
CXL VFIO passthrough needs a stable guest physical address range for
device memory (DPA) that falls inside a CFMWS entry the guest discovers
from ACPI CEDT. Without a dedicated range in the address map, the HDM
decoder has nowhere to point.

Add VIRT_HIGH_CXL_MMIO immediately after the second PCIe MMIO window.
It gets its own highmem_cxl_mmio flag in VirtMachineState rather than
sharing highmem_cxl, so the two slots are independently controllable
even though both are currently tied to CXL bridge presence.

The base and size flow through GPEXConfig.cxl_mmio to
acpi_dsdt_add_gpex(), which carves out a QWord memory descriptor in the
first CXL root bridge's _CRS. The CFMWS window is system-wide, so only
the first CXL bridge gets the descriptor - subsequent ones would
produce duplicate resource claims for the same range.

build_crs() already emits the bridge's own 64-bit ranges into crs.
The CFMWS window is a separate system-wide range, so only that window
is appended as a new QWord descriptor; the bridge ranges are not
re-emitted. A warn_report() fires if the CFMWS window overlaps any
existing bridge 64-bit range, since that would indicate an address
layout conflict.

Signed-off-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Manish Honap <mhonap@nvidia.com>
(backported from https://lore.kernel.org/all/20260427181235.3003865-1-mhonap@nvidia.com/)
[jan: Resolve #include conflict with hw/acpi/acpi_egm_memory.h added by nvidia_unstable-10.1 base; keep both includes]
Signed-off-by: Jiandi An <jan@nvidia.com>
(backported from 7831a4a https://github.com/JiandiAnNVIDIA/QEMU/tree/vfio-cxl-2026-05-21)
[kobak: Resolved the 11.0 include layout by keeping the existing ACPI EGM include and adding the CXL host MMIO plumbing.]
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Before this patch, pxb-cxl bridges had no _DSM method at all. When the
OS called _DSM on a CXL host bridge, ACPI returned an error and the OS
defaulted to reassigning resources across suspend/resume. On machines
where firmware pre-commits the HDM decoder, that reassignment breaks the
DPA mapping.

Wire preserve_config through GPEXConfig into build_cxl_osc_method() so
pxb-cxl host bridges get a _DSM method that signals the OS to keep
resource assignments stable when needed. The _DSM function 5 (preserve
firmware PCI configuration) is the mechanism used to convey this.

build_pci_host_bridge_dsm_method() is promoted from static to exported
so cxl.c can call it without duplicating the AML.

The x86 build_cxl_osc_method() call site passes false since x86 does
not use firmware-committed HDM decoders.

build_cxl_osc_method is renamed to acpi_dsdt_add_cxl_host_bridge_methods
The function now appends both the CXL _OSC method and the _DSM method,
so its old name is misleading. Renamed it to match the pxb-pcie analogue
acpi_dsdt_add_host_bridge_methods(), making the two root bridge code
paths symmetric. No AML change.

Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Signed-off-by: Manish Honap <mhonap@nvidia.com>
(backported from https://lore.kernel.org/all/20260427181235.3003865-1-mhonap@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
(cherry-picked from a8cf3b4 https://github.com/JiandiAnNVIDIA/QEMU/tree/vfio-cxl-2026-05-21)
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
… passthrough

Sync the VFIO UAPI additions from the kernel CXL Type-2 passthrough
series.

VFIO_DEVICE_FLAGS_CXL (bit 9) marks a device as CXL Type-2 and
guarantees the capability chain includes a vfio_device_info_cap_cxl
entry (cap id 6). That capability carries the BAR index holding the
CXL component registers, flags for firmware-committed and cache-capable
devices, the byte offset to the HDM Decoder Capability block within
that BAR, and region indices for both the DPA memory region and the
Component Register shadow.

Two new region subtypes:
  VFIO_REGION_SUBTYPE_CXL (1): mmappable DPA memory
  VFIO_REGION_SUBTYPE_CXL_COMP_REGS (2): HDM decoder shadow, r/w only

Note: UAPI headers are normally kept in sync via
scripts/update-linux-headers.sh once upstream kernel changes merge.
This patch manually adds the CXL Type-2 additions as a temporary
measure to unblock QEMU development. It should be dropped and
replaced with a proper header sync once the kernel series is accepted.

Signed-off-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Manish Honap <mhonap@nvidia.com>
(backported from https://lore.kernel.org/all/20260427181235.3003865-1-mhonap@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
(cherry-picked from 076f74c https://github.com/JiandiAnNVIDIA/QEMU/tree/vfio-cxl-2026-05-21)
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…or custom region ops

vfio_region_setup() always initializes the region MemoryRegion with
vfio_region_ops. CXL needs custom pread/pwrite ops for the Component
Register shadow region.

Add vfio_region_setup_with_ops() which accepts a const MemoryRegionOps *
parameter. When non-NULL it is passed to memory_region_init_io(); when
NULL the existing vfio_region_ops is used. vfio_region_setup() is
retained unchanged as a thin wrapper for all existing callers.

Signed-off-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Manish Honap <mhonap@nvidia.com>
(backported from https://lore.kernel.org/all/20260427181235.3003865-1-mhonap@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
(backported from 37cad16 https://github.com/JiandiAnNVIDIA/QEMU/tree/vfio-cxl-2026-05-21)
[kobak: Kept the custom region-ops helper, addressed the review finding by retaining sparse-mmap unwind, and preserved vfio_device_get_region_info() borrowed ownership instead of adding unsafe g_autofree cleanup.]
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…egion setup

When VFIO_DEVICE_FLAGS_CXL is set, the kernel has identified a CXL
Type-2 device and populated the capability chain with a
vfio_device_info_cap_cxl entry. Read that entry to locate the DPA
and CXL Component Register shadow regions, then call vfio_region_setup()
for each.

DPA covers the device's host-managed memory and is faulted in lazily
by the VMM. The CXL Component Register shadow gives the VMM access to
the HDM Decoder Capability block so it can intercept decoder commits
without touching the hardware register page directly.

vfio_cxl_derive_hdm_info() walks the CXL Capability Array inside the
Component Register shadow to find the HDM Decoder capability (ID 0x5)
and extracts hdm_decoder_offset and hdm_count. All reads use
le32_to_cpu() since the capability array is little-endian per the CXL
spec.  Dword 0 is the array header; capability entries start at dword 1,
which is why the loop begins at i = 1.

CXL register constants are defined here using names that mirror
<linux/cxl.h> to make cross-referencing straightforward.

Add the VFIOCXL struct embedded in VFIOPCIDevice.

Signed-off-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Manish Honap <mhonap@nvidia.com>
(backported from https://lore.kernel.org/all/20260427181235.3003865-1-mhonap@nvidia.com/)
[jan: Resolve include path conflict (nvidia_unstable-10.1 uses hw/hw.h and hw/iommu.h not yet renamed to hw/core/); add VMChangeStateEntry vmstate field from base; Reject non-firmware-committed CXL devices early in vfio_cxl_setup(); add machine_done notifier cleanup in vfio_pci_put_device() to prevent use-after-free on teardown; Fix double-errp in CXL DPA and COMP_REGS setup; use error_prepend instead of error_setg since vfio_region_setup already sets errp]
Signed-off-by: Jiandi An <jan@nvidia.com>
(backported from e312bc7 https://github.com/JiandiAnNVIDIA/QEMU/tree/vfio-cxl-2026-05-21)
[kobak: Resolved 11.0 include and VFIOPCIDevice state layout, kept only VFIOCXL cxl, preserved firmware-committed/error propagation fixes, and kept DPA/COMP_REGS region-info ownership borrowed.]
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…COMP_REGS overlay

The CXL Component Register BAR contains two types of ranges that need
different handling:

  - Accelerator register windows: passed through as direct hardware
    mmaps for performance. The kernel reports the real BAR size and
    lists mmappable windows via VFIO_REGION_INFO_CAP_SPARSE_MMAP,
    excluding the HDM Decoder Capability block. vfio_region_mmap()
    creates hardware-backed sub-regions for each sparse area.

  - HDM Decoder Capability block: guest accesses must go through
    emulated ops so QEMU can observe and program decoder state. The
    kernel blocks direct mmap of this range.

vfio_bar_register(): after the normal mmap path, overlay the COMP_REGS
emulation region at hdm_regs_offset with priority 1. In QEMU's
MemoryRegion model, overlapping subregions are resolved by priority;
the default is 0. Priority 1 ensures guest accesses to the HDM range
always dispatch through the emulated COMP_REGS ops regardless of any
hardware-backed sub-region at a neighbouring offset.

vfio_pci_bars_exit(): remove the COMP_REGS overlay before the normal
BAR teardown path.

Signed-off-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Manish Honap <mhonap@nvidia.com>
(backported from https://lore.kernel.org/all/20260427181235.3003865-1-mhonap@nvidia.com/)
[jan: Resolve pci_register_bar conflict; nvidia_unstable-10.1 uses &vdev->pdev not local pdev variable]
Signed-off-by: Jiandi An <jan@nvidia.com>
(backported from ae09b90 https://github.com/JiandiAnNVIDIA/QEMU/tree/vfio-cxl-2026-05-21)
[kobak: Resolved the 11.0 BAR registration shape while preserving the COMP_REGS overlay.]
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
… for firmware-committed devices

setup_locked_hdm() runs as a machine_done notifier after all devices
have been realized. It programs HDM decoder 0 with the CFMWS base
address so the guest can fault into device memory from the first
instruction.

The notifier is only registered when the kernel reports the device as
firmware-committed (VFIO_CXL_CAP_FIRMWARE_COMMITTED). The host is
responsible for HDM decoder programming; the guest has no mechanism to
remap host physical address mappings.

The function uses cxl_fmws_base captured by cxl_fmws_set_memmap() during
machine memory-map init. If no CFMWS base is available, it warns and
returns without programming anything.

If COMMIT_LOCK is set in decoder 0 CTRL at machine_done time (left-over
from a prior FLR?), it is cleared before writing BASE so the subsequent
write is not blocked. COMMIT_LOCK is re-set after programming so the
hardware enforces the committed base.

read_region() return is checked; failure aborts programming rather than
leaving ctrl uninitialized. All write_region() failures are propagated.
The function exits cleanly rather than leaving the decoder half-programmed.

Add cxl_fmws_base as a hwaddr global in cxl-host.c (and a stub in
cxl-host-stubs.c). It is set once by cxl_fmws_set_memmap() and read
later at machine_done time.

Signed-off-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Manish Honap <mhonap@nvidia.com>
(backported from https://lore.kernel.org/all/20260427181235.3003865-1-mhonap@nvidia.com/)
[jan: Set machine_done_registered flag after motifier registration for safe cleanup]
Signed-off-by: Jiandi An <jan@nvidia.com>
(backported from c091724 https://github.com/JiandiAnNVIDIA/QEMU/tree/vfio-cxl-2026-05-21)
[kobak: Preserved safe machine_done cleanup and the explicit VFIO-CXL DPA overlap over CFMWS. CFMWS count/size validation is kept in the later FMWS placement fix so this commit remains bisectable.]
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…y bus

The SMMUv3 primary bus check only accepted pxb-pcie as a valid root.
pxb-cxl uses the same PCIe-compatible bus implementation; reject it
and CXL devices behind it cannot reach the IOMMU.

Extend the check to also accept CXL buses so SMMUv3 translation applies
to passthrough CXL devices. Update the comment above the check to
mention pxb-cxl alongside pxb-pcie.

Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Signed-off-by: Manish Honap <mhonap@nvidia.com>
(backported from https://lore.kernel.org/all/20260427181235.3003865-1-mhonap@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
(backported from 1e4510b https://github.com/JiandiAnNVIDIA/QEMU/tree/vfio-cxl-2026-05-21)
[kobak: Adapted the pxb-cxl primary-bus check to the 11.0 SMMUv3 bus matching code.]
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…-device regions

vfio_container_region_add() attempts an IOMMU DMA mapping for every
RAM section that enters the guest address space. For VFIO mmap-backed
regions (PCI BAR windows, CXL.mem regions), this mapping always fails:
the backing VMAs carry VM_IO | VM_PFNMAP flags and pin_user_pages()
refuses to pin VM_IO pages, so IOMMU_IOAS_MAP returns -EFAULT.

CPU access to these regions goes through KVM Stage-2 page faults
independently of the SMMU/IOMMU, so no IOMMU entry is required for
correct operation.

Add an early return for RAM-device sections owned by a VFIO device.
vfio_get_vfio_device(memory_region_owner(section->mr)) returns non-NULL
for any mmap subregion created by vfio_region_mmap(), since
memory_region_init_ram_device_ptr() propagates the VFIOPCIDevice owner
from the containing region. Matching on ownership covers both normal
PCI BAR windows and CXL.mem regions uniformly; non-VFIO RAM-device
regions such as NVDIMMs are unaffected and continue through the normal
mapping path.

Signed-off-by: Manish Honap <mhonap@nvidia.com>
(backported from https://lore.kernel.org/all/20260427181235.3003865-1-mhonap@nvidia.com/)
Signed-off-by: Jiandi An <jan@nvidia.com>
(backported from 695286c https://github.com/JiandiAnNVIDIA/QEMU/tree/vfio-cxl-2026-05-21)
[kobak: Adapted the VFIO-owned RAM-device skip to the 11.0 listener ownership path.]
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Validation found that the ARM CXL highmem state was set after the
compact highmem layout decision. That left the CXL MMIO window and ACPI
exposure vulnerable to disagreeing with the actual memory map. The same
check found cxl_fmws_base, cxl_fmws_size, and the placed-window count
could be treated as valid before a CFMWS had actually been placed.

Set the ARM CXL highmem flags before the compact highmem layout is
computed, and only advertise the CXL MMIO window through ACPI when that
window remains enabled. Only publish cxl_fmws_base after a CFMWS is
actually placed, record the first placed CFMWS size and placed-window
count, skip unplaced CFMWS windows when building CEDT/MMIO mappings,
and reject multiple VFIO-CXL DPA mappings while the implementation
still has a single global fallback window.

Fixes: 5b3ffc5 ("NVIDIA: VR: SAUCE: hw/arm/virt: Add CXL FMWS PA window for device memory")
Fixes: 1e536ed23d ("NVIDIA: VR: SAUCE: hw/vfio+cxl: Program HDM decoder 0 at machine_done for firmware-committed devices")
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
The VFIO-CXL fallback path provides one global CFMWS window. A
second firmware-committed VFIO-CXL device could otherwise proceed far
enough for the later machine_done path to discover the conflict, which
is too late for clean realize-time error propagation.

Reject a second firmware-committed VFIO-CXL device during setup while
only one global CFMWS fallback window is available. Reserve the window
in the error-propagating setup path and release it during device teardown,
instead of letting machine_done warn after realization. Keep
the CFMWS placed-window count and first-window size populated so
machine_done can validate the DPA mapping against the CFMWS window.

Fixes: 1e536ed23d ("NVIDIA: VR: SAUCE: hw/vfio+cxl: Program HDM decoder 0 at machine_done for firmware-committed devices")
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
The duplicate-FMWS check still ran after BAR and CXL region population.
That meant duplicate users of the single global CFMWS fallback could fail
through a deeper setup path after state had already been populated.

Reserve the single global CFMWS fallback immediately after VFIO attach,
before BAR and CXL regions are populated. This makes duplicate VFIO-CXL
users fail through the shallow realize error path without leaking setup
state. Preserve the placed-window count and first-window size so
machine_done can validate the DPA mapping against the selected CFMWS.

Fixes: 1e536ed23d ("NVIDIA: VR: SAUCE: hw/vfio+cxl: Program HDM decoder 0 at machine_done for firmware-committed devices")
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Guest log before this fix:

  pci 0000:34:00.0: bridge window [mem size 0xc000000000 64bit pref]: can't assign; no space
  pci 0000:35:00.0: BAR 2 [mem size 0x8000000000 64bit pref]: failed to assign
  pci 0000:35:00.0: BAR 0 [mem size 0x10000000 64bit pref]: failed to assign
  pci 0000:35:00.0: BAR 4 [mem size 0x02000000 64bit pref]: failed to assign

The virt highmem-mmio-size property only resized the PCIe high MMIO
window. Keep the CXL high MMIO window in sync too, so large VFIO-CXL
Type-2 BARs have enough guest bridge aperture when the machine is booted
with a larger highmem-mmio-size.

After rebuilding QEMU and booting with highmem-mmio-size=1T, the guest
assigned the endpoint memory BARs:

  pci 0000:35:00.0: BAR 2 [mem 0x20000000000-0x27fffffffff 64bit pref]: assigned
  pci 0000:35:00.0: BAR 0 [mem 0x28000000000-0x2800fffffff 64bit pref]: assigned
  pci 0000:35:00.0: BAR 4 [mem 0x28010000000-0x28011ffffff 64bit pref]: assigned

Fixes: 5b3ffc5 ("NVIDIA: VR: SAUCE: hw/arm/virt: Add CXL FMWS PA window for device memory")
Signed-off-by: Koba Ko <kobak@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Current workflow actions are deprecated, this updates them to newer versions.

Signed-off-by: Morgan Hunter <morgan.hunter@canonical.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…wned RAM-device regions"

This reverts commit be3d015.

The commit added an early return in vfio_container_region_add() for any
RAM-device section owned by a VFIO device
(vfio_get_vfio_device(memory_region_owner(section->mr)) != NULL), skipping
vfio_container_dma_map() for it. In practice that excludes every VFIO mmap
subregion from the IOMMU IOAS (the SMMU Stage-2 page tables): PCI BAR
windows, and the CXL.mem coherent device memory of a CXL Type-2 device.

The commit was added becuase for earlier testing during device boot,
I was seeing these errors in the QEMU log:

qemu-system-aarch64: warning: IOMMU_IOAS_MAP failed: Bad address, PCI BAR?

While testing with kernel 6.17.9, I only had tested with the CXL mode
and only CUDA tests. This was a testing miss on my side.
During testing, I had missed to test UVM ATS tests and verification of
PCI-E mode with my QEMU patches.

Earlier during debugging I misdiagnosed the issue to be the mapping was
always failing as the backing VMAs are VM_IO | VM_PFNMAP, pin_user_pages()
refused VM_IO pages, and IOMMU_IOAS_MAP therefore returns -EFAULT resulting
in failure. For overcoming this failure, I had added the mapping skip
part. This was not correct and the skip seems to break CUDA UVM ATS on CXL
Type-2 passthrough.

The bug caused by mapping skip
------------------------------
In accelerated nested SMMUv3 mode the GPU translates shared virtual
addresses through the hardware SMMU (Stage-1 is the guest page tables,
Stage-2 is the host iommufd tables). When CUDA UVM migrates a managed
buffer into the device's coherent memory, that page's guest-physical
address lies in the CXL HDM window. The GPU reaches it with an ATS request,
and to answer that request the SMMU must complete the Stage-1 and Stage-2
walk. With the HDM region skipped there is no Stage-2 entry, so the
translation faults. The GPU posts a replayable fault, UVM services it and
replays, the access faults again, and the GPU spins in a
fault/service/replay livelock. The guest test hangs, and on cancel it
reports "Xid 31 ... FAULT_PTE ACCESS_TYPE_VIRT_WRITE". Non-ATS workloads
and PCI-E-mode (nvgrace-gpu) passthrough are unaffected, because they never
reach the unmapped path.

IOMMU_IOAS_MAP is now succeeding for VM_PFNMAP GPU device memory on kernel
6.17.13 because of the host-side workaround

    68a70c30f8ce ("NVIDIA: SAUCE: WAR: iommufd/pages: Bypass PFNMAP")

That patch teaches iommufd's pfn_reader to handle VM_PFNMAP VMAs. Instead
of pin_user_pages() (which does refuse VM_IO), it calls follow_fault_pfn(),
which uses follow_pfnmap_start(), faults the lazily inserted PFN in through
fixup_user_fault(), and takes the raw struct-page-less PFN. d814's premise
was therefore only true on a kernel without this workaround. With it
present, IOMMU_IOAS_MAP for the HDM region returns success (0), as the QEMU
trace shows:

    iommufd_backend_map_dma ... iova=0x80000000000 size=0x2330000000 ... readonly=0 (0)

I will check in next series of vfio-cxl QEMU support series if any additional
fix is required for this.

Signed-off-by: Manish Honap <mhonap@nvidia.com>
Acked-by: Shameer Kolothum <skolothumtho@nvidia.com>
Acked-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
(cherry picked from commit c6d9738 nvidia_unstable-10.1)
[mochs: Updated reverted commit SHA to match commit on this branch]
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
This reverts commit 306482a.

The early FMWS reservation only guards the single global CFMWS window. Per-device
window selection later in this series replaces that model, so drop it.

Signed-off-by: Manish Honap <mhonap@nvidia.com>
This reverts commit ce49836.

Rejecting a second VFIO-CXL device is only needed because of the single global
CFMWS window. Per-device selection later in this series supports many devices,
so drop it.

Signed-off-by: Manish Honap <mhonap@nvidia.com>
…i.c only)

Revert the hw/vfio/pci.c part of commit af8aa96. It added the
vfio_cxl_fmws_in_use flag that rejects a second VFIO-CXL device while only one
global CFMWS window is available. The next patch replaces that with per-device
window selection, so drop it.

The rest of af8aa96 is kept: fw->placed tracking, the CEDT and MMIO handling
of placed windows, and the ARM highmem flag ordering.

Signed-off-by: Manish Honap <mhonap@nvidia.com>
…vice CFMWS base

setup_locked_hdm() programmed every firmware-committed VFIO-CXL device at the
first placed CFMWS base. With more than one passthrough GPU, each behind its
own pxb-cxl and its own single-target CFMWS, every device landed at window 0's
base. In the guest all endpoint decoders then report the same HPA, so only the
first region attaches and the other GPU drivers fail to initialize.

Select the window that targets the device instead. The host bridge is the
parent of the device's root bus (pci_device_root_bus()->parent_dev, the pxb-cxl
for a directly attached endpoint), matched against each window's target. This
is by topology, not window index, so N devices land in N windows.

Only a unique single-target CFMWS is supported. vfio_cxl_program_locked_hdm()
requires such a match, and the machine_done notifier turns any error into a
fatal startup failure. It rejects no match, an ambiguous host bridge, an
interleaved window, an unplaced window, a window smaller than the device DPA,
and a window already used by another endpoint.

Match on fw->targets[] (names) rather than fw->target_hbs[] (pointers), which
cxl_fmws_link_targets() fills from a machine_done notifier that may run after
this one.

Reject hot-add of a VFIO-CXL device: for a post-boot device_add the notifier
runs synchronously and its exit() on error would kill the running guest, while
the CFMWS/HDM model is fixed at machine startup.

hw/vfio/pci.c builds without CONFIG_CXL, so add a cxl_fmws_get_all_sorted()
stub to hw/cxl/cxl-host-stubs.c for the link.

Map the DPA region with memory_region_add_subregion_overlap(): on this branch
the CFMWS window is mapped into system memory at fw->base.

TODO: only a direct topology is handled. An endpoint behind a CXL switch is not
detected or rejected.

Fixes: c6267fb3d0d4 ("NVIDIA: VR: SAUCE: hw/vfio+cxl: Program HDM decoder 0 at machine_done for firmware-committed devices")
Signed-off-by: Manish Honap <mhonap@nvidia.com>
cxl_fmws_base, cxl_fmws_size and cxl_fmws_count described the single global
CFMWS window. Per-device selection now reads fw->base, fw->size and
fw->num_targets from the matched window, so nothing reads these globals.

Remove them and the first-window bookkeeping in cxl_fmws_set_memmap(). The
per-window fw->placed flag stays; cxl_build_cedt() and cxl_fmws_mmio_map()
still use it.

Signed-off-by: Manish Honap <mhonap@nvidia.com>
@NathanChenNVIDIA

Copy link
Copy Markdown
Collaborator

LGTM
Acked-by: Nathan Chen <nathanc@nvidia.com>

@JiandiAnNVIDIA

Copy link
Copy Markdown
Collaborator

Acked-by: Jiandi An jan@nvidia.com

@JiandiAnNVIDIA

Copy link
Copy Markdown
Collaborator

Merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.