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]> --- 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 */ -- 2.25.1
