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

