> -----Original Message-----
> From: Alex Williamson <[email protected]>
> Sent: 11 July 2026 03:53
> To: Manish Honap <[email protected]>
> Cc: [email protected]; [email protected]; [email protected];
> [email protected]; Ankit Agrawal <[email protected]>;
> [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; Neo Jia <[email protected]>; Krishnakant Jaju
> <[email protected]>; Vikram Sethi <[email protected]>; Zhi Wang
> <[email protected]>; [email protected]; [email protected];
> [email protected]; [email protected]; linux-
> [email protected]; [email protected]
> Subject: Re: [PATCH v3 08/11] vfio/pci/cxl: Add HDM + COMP_REGS regions
> and DVSEC clipping shim
>
> External email: Use caution opening links or attachments
>
>
> On Thu, 25 Jun 2026 22:24:04 +0530
> <[email protected]> wrote:
> > diff --git a/drivers/vfio/pci/vfio_pci_config.c
> > b/drivers/vfio/pci/vfio_pci_config.c
> > index a10ed733f0e3..b9f30a33515a 100644
> > --- a/drivers/vfio/pci/vfio_pci_config.c
> > +++ b/drivers/vfio/pci/vfio_pci_config.c
> > @@ -1898,8 +1898,15 @@ ssize_t vfio_pci_config_rw_single(struct
> vfio_pci_core_device *vdev,
> > /*
> > * Chop accesses into aligned chunks containing no more than a
> > * single capability. Caller increments to the next chunk.
> > + *
> > + * For CXL Type-2 devices also clip at the CXL Device DVSEC body
> > + * boundary so the generic perm-bits path handles the DVSEC
> > + * header bytes and the CXL hook handles the body bytes; without
> > + * this clip a 32-bit access at dvsec + 0x08 would span the
> > + * generic Header2 word and the CXL CAPABILITY word.
> > */
> > count = min(count, vfio_pci_cap_remaining_dword(vdev, *ppos));
> > + count = min(count, vfio_pci_cxl_config_boundary(vdev, *ppos));
> > if (count >= 4 && !(*ppos % 4))
> > count = 4;
> > else if (count >= 2 && !(*ppos % 2)) @@ -1909,6 +1916,30 @@
> > ssize_t vfio_pci_config_rw_single(struct vfio_pci_core_device *vdev,
> >
> > ret = count;
> >
> > + /*
> > + * Give the CXL Type-2 hook first claim on this access: if the
> > + * range lies inside the CXL Device DVSEC body, forward it to
> > + * cxl-core's register-virtualization helpers instead of the
> > + * standard perm-bits path. -ENOENT means "not for me; use the
> > + * default path"; any other negative value is a hard error.
> > + */
> > + if (vdev->cxl) {
> > + __le32 le_val = 0;
> > + ssize_t cxl_ret;
> > +
> > + if (iswrite && copy_from_user(&le_val, buf, count))
> > + return -EFAULT;
> > + cxl_ret = vfio_pci_cxl_config_rw(vdev, *ppos, count,
> &le_val,
> > + iswrite);
> > + if (cxl_ret >= 0) {
> > + if (!iswrite && copy_to_user(buf, &le_val,
> count))
> > + return -EFAULT;
> > + return cxl_ret;
> > + }
> > + if (cxl_ret != -ENOENT)
> > + return cxl_ret;
> > + }
> > +
>
> I think the solution here is just to set the .readfn and .writefn for
> PCI_EXT_CAP_ID_DVSEC to dvsec specific handlers, rather than the raw
> write and direct read handlers. The new handlers would detect whether
> the reference is to the CXL DVSEC body, possibly via ranges stored in
> vdev->cxl, and either call through to CXL handlers via cxl_ops
> (previously suggested), or fall through to the raw/direct handlers.
okay, I will have handling for this in v4.
>
> > cap_id = vdev->pci_config_map[*ppos];
> >
> > if (cap_id == PCI_CAP_ID_INVALID) { diff --git
> > a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
> > index 05ab4ae59157..2d2dae278d1e 100644
> > --- a/drivers/vfio/pci/vfio_pci_core.c
> > +++ b/drivers/vfio/pci/vfio_pci_core.c
> > @@ -501,6 +501,23 @@ static void vfio_pci_core_map_bars(struct
> vfio_pci_core_device *vdev)
> > if (!pci_resource_len(pdev, i))
> > continue;
> >
> > + /*
> > + * cxl-core already holds request_mem_region() on the
> CXL
> > + * component register sub-range of this BAR. Skip the
> > + * full-BAR request so we do not collide with that
> > + * sub-region; vfio still owns the BAR via the driver
> > + * binding and the iomap below succeeds without a region
> > + * claim.
> > + */
> > + if (vdev->cxl && bar ==
> vfio_pci_cxl_get_component_reg_bar(vdev)) {
> > + vdev->barmap[bar] = pci_iomap(pdev, bar, 0);
> > + if (!vdev->barmap[bar]) {
> > + pci_dbg(pdev, "Failed to iomap region
> %d\n", bar);
> > + vdev->barmap[bar] = IOMEM_ERR_PTR(-
> ENOMEM);
> > + }
> > + continue;
> > + }
> > +
> > if (pci_request_selected_regions(pdev, 1 << bar,
> "vfio")) {
> > pci_dbg(pdev, "Failed to reserve region %d\n",
> bar);
> > vdev->barmap[bar] = IOMEM_ERR_PTR(-EBUSY); @@
> > -701,7 +718,10 @@ void vfio_pci_core_disable(struct
> vfio_pci_core_device *vdev)
> > if (IS_ERR_OR_NULL(vdev->barmap[bar]))
> > continue;
> > pci_iounmap(pdev, vdev->barmap[bar]);
> > - pci_release_selected_regions(pdev, 1 << bar);
> > + /* Mirror the asymmetric setup-time skip in map_bars().
> */
> > + if (!(vdev->cxl &&
> > + i == vfio_pci_cxl_get_component_reg_bar(vdev)))
> > + pci_release_selected_regions(pdev, 1 << bar);
>
> It would be much less ugly to create
> vfio_pci_{request,release}_selected_region() wrappers that mask whether
> the region is actually requested or released than to disrupt the code
> flow like this. Likewise below, think about creating wrappers that do
> the right thing for cxl and are no-ops otherwise. For example, embed
> the vdev->cxl test into the function to cleanup the callers. Thanks,
>
Agreed. I will add helper routines for this as suggested.
> Alex
>
> > vdev->barmap[bar] = NULL;
> > }
> >
> > @@ -1051,6 +1071,16 @@ static int vfio_pci_ioctl_get_info(struct
> vfio_pci_core_device *vdev,
> > info.num_regions = VFIO_PCI_NUM_REGIONS + vdev->num_regions;
> > info.num_irqs = VFIO_PCI_NUM_IRQS;
> >
> > + if (vdev->cxl) {
> > + ret = vfio_pci_cxl_get_info(vdev, &caps);
> > + if (ret) {
> > + pci_warn(vdev->pdev,
> > + "Failed to add CXL info capability\n");
> > + return ret;
> > + }
> > + info.flags |= VFIO_DEVICE_FLAGS_CXL;
> > + }
> > +
> > ret = vfio_pci_info_zdev_add_caps(vdev, &caps);
> > if (ret && ret != -ENODEV) {
> > pci_warn(vdev->pdev,
> > @@ -1093,6 +1123,12 @@ int vfio_pci_ioctl_get_region_info(struct
> vfio_device *core_vdev,
> > struct pci_dev *pdev = vdev->pdev;
> > int i, ret;
> >
> > + if (vdev->cxl) {
> > + ret = vfio_pci_cxl_get_region_info(vdev, info, caps);
> > + if (ret != -ENOTTY)
> > + return ret;
> > + }
> > +
> > switch (info->index) {
> > case VFIO_PCI_CONFIG_REGION_INDEX:
> > info->offset = VFIO_PCI_INDEX_TO_OFFSET(info->index);