On 9/16/26 20:44, [email protected] wrote:
From: Manish Honap <[email protected]>
The kernel marks a passthroughed CXL Type-2 device with a device flag and
exposes two regions:
- HDM memory (host physical)
- the trapped HDM decoder register block.
Read the flag, locate both regions by type, and take the component BAR
and block offset from the geometry capability. Realize only records this;
later patches build the guest mapping on top.
AI-used-for: code (prototype)
Signed-off-by: Manish Honap <[email protected]>
LGTM.
Thanks,
C.
---
hw/vfio/pci.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
hw/vfio/pci.h | 15 +++++++++++
2 files changed, 87 insertions(+)
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 428ab2f069..2f84af5cf8 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -3570,6 +3570,64 @@ bool vfio_pci_interrupt_setup(VFIOPCIDevice *vdev, Error
**errp)
return true;
}
+/*
+ * Learn the CXL geometry the kernel reports: the HPA-backed HDM memory region
+ * and the trapped HDM decoder block (which BAR carries it and at what offset).
+ * A non-CXL device leaves cxl.enabled false and takes no CXL paths.
+ */
+static bool vfio_cxl_setup(VFIOPCIDevice *vdev, Error **errp)
+{
+ VFIODevice *vbasedev = &vdev->vbasedev;
+ VFIOCXL *cxl = &vdev->cxl;
+ struct vfio_region_info *mem_info = NULL, *comp_info = NULL;
+ struct vfio_region_info_cap_cxl_comp_regs *cap;
+ struct vfio_info_cap_header *hdr;
+
+ if (!(vbasedev->flags & VFIO_DEVICE_FLAGS_CXL)) {
+ return true;
+ }
+
+ if (vfio_device_get_region_info_type(vbasedev,
+ VFIO_REGION_TYPE_PCI_VENDOR_TYPE |
+ CXL_VENDOR_ID,
+ VFIO_REGION_SUBTYPE_CXL_MEM,
+ &mem_info)) {
+ error_setg(errp, "vfio-cxl: %s: CXL memory region not found",
+ vbasedev->name);
+ return false;
+ }
+
+ if (vfio_device_get_region_info_type(vbasedev,
+ VFIO_REGION_TYPE_PCI_VENDOR_TYPE |
+ CXL_VENDOR_ID,
+ VFIO_REGION_SUBTYPE_CXL_COMP_REGS,
+ &comp_info)) {
+ error_setg(errp,
+ "vfio-cxl: %s: CXL component-register region not found",
+ vbasedev->name);
+ return false;
+ }
+
+ hdr = vfio_get_region_info_cap(comp_info,
+ VFIO_REGION_INFO_CAP_CXL_COMP_REGS);
+ if (!hdr) {
+ error_setg(errp,
+ "vfio-cxl: %s: component-register geometry not reported",
+ vbasedev->name);
+ return false;
+ }
+ cap = container_of(hdr, struct vfio_region_info_cap_cxl_comp_regs, header);
+
+ cxl->mem_region_index = mem_info->index;
+ cxl->comp_regs_region_index = comp_info->index;
+ cxl->dpa_size = mem_info->size;
+ cxl->comp_bar = cap->bar;
+ cxl->hdm_offset = cap->offset;
+ cxl->enabled = true;
+
+ return true;
+}
+
static void vfio_pci_realize(PCIDevice *pdev, Error **errp)
{
ERRP_GUARD();
@@ -3700,6 +3758,20 @@ static void vfio_pci_realize(PCIDevice *pdev, Error
**errp)
}
}
+ if (!vfio_cxl_setup(vdev, errp)) {
+ /*
+ * vfio_migration_realize() above installed a migration blocker in auto
+ * mode (generic vfio-pci exposes no migration ops). out_deregister
does
+ * not remove it, so a rejected CXL setup would leave VM migration
+ * blocked until QEMU restarts. Drop it here, under the same
+ * failover-pair condition used to install it.
+ */
+ if (!pdev->failover_pair_id) {
+ vfio_migration_exit(vbasedev);
+ }
+ goto out_deregister;
+ }
+
vfio_pci_register_err_notifier(vdev);
vfio_pci_register_req_notifier(vdev);
vfio_setup_resetfn_quirk(vdev);
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index c9ab949870..7fdd695704 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -122,10 +122,25 @@ typedef struct VFIOMSIXInfo {
OBJECT_DECLARE_SIMPLE_TYPE(VFIOPCIDevice, VFIO_PCI_DEVICE)
+/*
+ * State for a CXL Type-2 device. The kernel owns the host physical placement
+ * of the device memory; QEMU only maps it at the guest physical address the
+ * guest commits into its endpoint HDM decoder.
+ */
+typedef struct VFIOCXL {
+ bool enabled;
+ uint32_t mem_region_index; /* HPA-backed HDM memory VFIO region */
+ uint32_t comp_regs_region_index; /* trapped HDM decoder register block */
+ uint32_t comp_bar; /* component BAR carrying that block */
+ uint64_t hdm_offset; /* block offset within the component BAR
*/
+ uint64_t dpa_size; /* size of the HDM memory region */
+} VFIOCXL;
+
struct VFIOPCIDevice {
PCIDevice parent_obj;
VFIODevice vbasedev;
+ VFIOCXL cxl;
VFIOINTx intx;
unsigned int config_size;
uint8_t *emulated_config_bits; /* QEMU emulated bits, little-endian */