From: Manish Honap <[email protected]>

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 <[email protected]>
---
 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


Reply via email to