[PATCH v4 16/27] vfio/cxl: Shadow the CXL DVSEC body at open
From: mhonap
Date: Thu Aug 13 2026 - 05:57:12 EST
From: Manish Honap <mhonap@xxxxxxxxxx>
Sample the CXL DVSEC body into a per-open shadow when the guest opens the
device, and free it at close. Reading it here rather than at bind picks
up any change from a low-power transition, and gives the DVSEC access
handler added next a per-tenant copy to serve from.
Annotate the shadow with __counted_by_ptr(dvsec_dwords) so its accesses
are bounds-checked against the recorded dword count.
Signed-off-by: Manish Honap <mhonap@xxxxxxxxxx>
---
drivers/vfio/pci/cxl/vfio_cxl_core.c | 39 ++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/drivers/vfio/pci/cxl/vfio_cxl_core.c b/drivers/vfio/pci/cxl/vfio_cxl_core.c
index d19fd638f538..2e516a0929c6 100644
--- a/drivers/vfio/pci/cxl/vfio_cxl_core.c
+++ b/drivers/vfio/pci/cxl/vfio_cxl_core.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/range.h>
+#include <linux/slab.h>
#include <linux/vfio_pci_core.h>
#include <cxl/cxl.h>
#include <cxl/pci.h>
@@ -17,11 +18,19 @@
* @cxlds: CXL device state; kept first for devm_cxl_dev_state_create()
* @cxlmd: memory device joined to the CXL topology at bind
* @hpa_range: host physical range of the HDM region
+ * @dvsec: CXL device DVSEC config-space offset
+ * @dvsec_len: length of the DVSEC body
+ * @dvsec_dwords: dword count of @dvsec_shadow
+ * @dvsec_shadow: guest view of the CXL DVSEC body, sampled at open
*/
struct vfio_cxl_state {
struct cxl_dev_state cxlds;
struct cxl_memdev *cxlmd;
struct range hpa_range;
+ u16 dvsec;
+ u32 dvsec_len;
+ u32 dvsec_dwords;
+ u32 *dvsec_shadow __counted_by_ptr(dvsec_dwords);
};
static int vfio_cxl_init_device(struct vfio_pci_core_device *vdev)
@@ -71,6 +80,8 @@ static int vfio_cxl_init_device(struct vfio_pci_core_device *vdev)
if (!cxl)
return -ENOMEM;
+ cxl->dvsec = dvsec;
+
/*
* vfio-pci requests the whole component BAR when the guest opens the
* device. Declare the BAR owned so the CXL core maps the HDM/RAS
@@ -102,11 +113,39 @@ static void vfio_cxl_release_device(struct vfio_pci_core_device *vdev)
static int vfio_cxl_open_device(struct vfio_pci_core_device *vdev)
{
+ struct vfio_cxl_state *cxl = vdev->cxl;
+ struct pci_dev *pdev = vdev->pdev;
+ u32 hdr, *shadow;
+ int i, dwords;
+
+ /*
+ * Sample the DVSEC body now rather than at bind: a low-power
+ * transition could have changed it since the device was bound.
+ */
+ pci_read_config_dword(pdev, cxl->dvsec + PCI_DVSEC_HEADER1, &hdr);
+ cxl->dvsec_len = PCI_DVSEC_HEADER1_LEN(hdr);
+ dwords = cxl->dvsec_len / sizeof(u32);
+
+ shadow = kcalloc(dwords, sizeof(u32), GFP_KERNEL);
+ if (!shadow)
+ return -ENOMEM;
+
+ for (i = 0; i < dwords; i++)
+ pci_read_config_dword(pdev, cxl->dvsec + i * sizeof(u32),
+ &shadow[i]);
+
+ cxl->dvsec_dwords = dwords;
+ cxl->dvsec_shadow = shadow;
+
return 0;
}
static void vfio_cxl_close_device(struct vfio_pci_core_device *vdev)
{
+ struct vfio_cxl_state *cxl = vdev->cxl;
+
+ kfree(cxl->dvsec_shadow);
+ cxl->dvsec_shadow = NULL;
}
static const struct vfio_cxl_ops vfio_cxl_ops = {
--
2.25.1