[PATCH v4 21/27] vfio/cxl: Describe the CXL device and decoder geometry to userspace

From: mhonap

Date: Thu Aug 13 2026 - 06:00:40 EST


From: Manish Honap <mhonap@xxxxxxxxxx>

Advertise the assignment with a device-info flag so a VMM can tell a
CXL Type-2 device apart from a plain vfio-pci one. On the trapped
component region, add a capability carrying the BAR and offset of the
HDM decoder registers so the VMM can place the window where the guest
expects to find it.

Signed-off-by: Manish Honap <mhonap@xxxxxxxxxx>
---
drivers/vfio/pci/cxl/vfio_cxl_core.c | 16 ++++++++++++++++
drivers/vfio/pci/vfio_pci_core.c | 3 +++
include/uapi/linux/vfio.h | 18 ++++++++++++++++++
3 files changed, 37 insertions(+)

diff --git a/drivers/vfio/pci/cxl/vfio_cxl_core.c b/drivers/vfio/pci/cxl/vfio_cxl_core.c
index ec938813bd91..0fb5ed5d86b7 100644
--- a/drivers/vfio/pci/cxl/vfio_cxl_core.c
+++ b/drivers/vfio/pci/cxl/vfio_cxl_core.c
@@ -381,9 +381,25 @@ static ssize_t vfio_cxl_comp_rw(struct vfio_pci_core_device *vdev,
return count;
}

+static int vfio_cxl_comp_add_capability(struct vfio_pci_core_device *vdev,
+ struct vfio_pci_region *region,
+ struct vfio_info_cap *caps)
+{
+ struct cxl_hdm_info *hdm = vdev->pdev->hdm;
+ struct vfio_region_info_cap_cxl_comp_regs cap = {
+ .header.id = VFIO_REGION_INFO_CAP_CXL_COMP_REGS,
+ .header.version = 1,
+ .bar = hdm->hdm_bar,
+ .offset = hdm->hdm_offset,
+ };
+
+ return vfio_info_add_capability(caps, &cap.header, sizeof(cap));
+}
+
static const struct vfio_pci_regops vfio_cxl_comp_regops = {
.rw = vfio_cxl_comp_rw,
.release = vfio_cxl_region_release,
+ .add_capability = vfio_cxl_comp_add_capability,
};

static void vfio_cxl_release_hpa(void *data)
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 6f6ebcce86a1..77f8f39dd670 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -1192,6 +1192,9 @@ static int vfio_pci_ioctl_get_info(struct vfio_pci_core_device *vdev,
if (vdev->reset_works)
info.flags |= VFIO_DEVICE_FLAGS_RESET;

+ if (vdev->cxl_ops)
+ info.flags |= VFIO_DEVICE_FLAGS_CXL;
+
info.num_regions = VFIO_PCI_NUM_REGIONS + vdev->num_regions;
info.num_irqs = VFIO_PCI_NUM_IRQS;

diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index d5b8106625bf..df88535ede5f 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -215,6 +215,7 @@ struct vfio_device_info {
#define VFIO_DEVICE_FLAGS_FSL_MC (1 << 6) /* vfio-fsl-mc device */
#define VFIO_DEVICE_FLAGS_CAPS (1 << 7) /* Info supports caps */
#define VFIO_DEVICE_FLAGS_CDX (1 << 8) /* vfio-cdx device */
+#define VFIO_DEVICE_FLAGS_CXL (1 << 9) /* vfio-cxl device */
__u32 num_regions; /* Max region index + 1 */
__u32 num_irqs; /* Max IRQ index + 1 */
__u32 cap_offset; /* Offset within info struct of first cap */
@@ -505,6 +506,23 @@ struct vfio_region_info_cap_nvlink2_lnkspd {
__u32 __pad;
};

+/*
+ * Geometry of a CXL Type-2 device's HDM decoder registers, so a VMM can place
+ * the trapped component register window where the guest expects it. The trapped
+ * region spans the whole HDM decoder block (every decoder), not just decoder 0:
+ * a VMM reads the decoder count and each decoder's committed base from the block
+ * itself. Additional trapped component capabilities, such as CXL RAS, are
+ * exposed as their own region subtypes rather than by extending this cap.
+ */
+#define VFIO_REGION_INFO_CAP_CXL_COMP_REGS 6
+
+struct vfio_region_info_cap_cxl_comp_regs {
+ struct vfio_info_cap_header header;
+ __u32 bar;
+ __u32 __resv; /* reserved, must be zero; versioning anchor for flags */
+ __aligned_u64 offset;
+};
+
/**
* VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9,
* struct vfio_irq_info)
--
2.25.1