> -----Original Message-----
> From: Dan Williams (nvidia) <[email protected]>
> Sent: 11 July 2026 03:39
> To: Manish Honap <[email protected]>; [email protected]; [email protected];
> [email protected]; [email protected]; [email protected]; Ankit Agrawal
> <[email protected]>; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected]
> Cc: Neo Jia <[email protected]>; Krishnakant Jaju <[email protected]>;
> Vikram Sethi <[email protected]>; Zhi Wang <[email protected]>; Manish
> Honap <[email protected]>; [email protected]; linux-
> [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
>
>
> mhonap@ wrote:
> > From: Manish Honap <[email protected]>
> >
> > Complete the vfio-pci-core integration of CXL Type-2 device
> > passthrough by exposing two VFIO regions to userspace, wiring DVSEC
> > config-space accesses through cxl-core's register-virtualization
> > helpers, and reserving the CXL component register block from BAR mmap
> > and BAR resource claim.
> >
> > HDM region (VFIO_REGION_SUBTYPE_CXL):
> > - mmappable view of the device's firmware-committed HPA range
> > - mmap fault handler calls vmf_insert_pfn() from the physical HPA
> > so the guest gets the same backing memory the host sees
> > - pread/pwrite go through the memremap_wb() kva captured at
> > bind time by vfio_cxl_map_hdm()
> >
> > COMP_REGS region (VFIO_REGION_SUBTYPE_CXL_COMP_REGS):
> > - pread/pwrite only, dword-aligned (-EINVAL on misalignment)
> > - thin transport: each dword dispatches by offset to
> > cxl_passthrough_cm_rw() (CM cap-array snapshot) or
> > cxl_passthrough_hdm_rw() (HDM Decoder block). No shadow buffer
> > on the vfio side; all per-field semantics live in cxl-core.
> >
> > DVSEC config-space access:
> > - vfio_pci_cxl_config_boundary() clips a chunk at the CXL Device
> > DVSEC body edge in vfio_pci_config_rw_single() so the generic
> > perm-bits path handles the DVSEC header bytes and the CXL hook
> > handles the body bytes. The clipping shim is used instead of
> > re-pointing the ecap_perms[] readfn/writefn (which would mutate
> > a module-init static and race across multiple CXL devices).
> > - vfio_pci_cxl_config_rw() forwards clipped accesses to
> > cxl_passthrough_dvsec_rw(); cxl-core enforces the per-field
> > write semantics (LOCK/RWO, CONTROL/RWL, STATUS/RW1C,
> > RANGE1/HwInit, RANGE2/RsvdZ).
> >
> > GET_INFO / GET_REGION_INFO:
> > - VFIO_DEVICE_INFO_CAP_CXL advertises the two region indices, the
> > component BAR layout, and HOST_FIRMWARE_COMMITTED.
> > - GET_REGION_INFO on the component BAR returns a sparse-mmap cap
> > that excludes [comp_reg_offset, comp_reg_offset+comp_reg_size).
> >
> > BAR resource handling:
> > - cxl-core holds request_mem_region() on the CXL component
> > register sub-range from devm_cxl_probe_mem(), so vfio_pci-core's
> > pci_request_selected_regions() on the full BAR would collide.
> > map_bars() skips the request for the component BAR (still iomaps
> > it; vfio holds the BAR via driver binding); disable() mirrors
> > the asymmetric skip.
> > - mmap of the component BAR refuses any range overlapping the CXL
> > sub-range via vfio_pci_cxl_mmap_overlaps_comp_regs().
> >
> > vfio_pci_cxl_open() now registers both VFIO regions; close()
> > unregisters them. Raw BAR rw redirect into the CXL sub-range is
> > intentionally not implemented: VMMs use the COMP_REGS region directly.
>
> I jumped ahead in the review to see how passthrough.c was being used.
>
> This patch is doing a lot which raises the risk that individual
> proposals within it are going to raise questions.
>
> > Signed-off-by: Manish Honap <[email protected]>
> > ---
> > drivers/vfio/pci/cxl/vfio_cxl_core.c | 521
> ++++++++++++++++++++++++++-
> > drivers/vfio/pci/vfio_pci_config.c | 31 ++
> > drivers/vfio/pci/vfio_pci_core.c | 44 ++-
> > drivers/vfio/pci/vfio_pci_priv.h | 72 ++++
> > drivers/vfio/pci/vfio_pci_rdwr.c | 17 +
> > 5 files changed, 679 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > b/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > index 42cd00bbe869..8a00b776d7c7 100644
> > --- a/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > +++ b/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > @@ -123,12 +123,24 @@ static int vfio_cxl_probe_regs(struct
> vfio_pci_cxl_state *cxl)
> > if (rc)
> > return rc;
> >
> > + /*
> > + * The CXL Component Register block is a fixed 64 KiB area (CXL
> r4.0
> > + * ยง8.2.3). cxl_pci_setup_regs() records the remaining BAR
> length
> > + * after the regblock offset in reg_map.max_size, which is an
> upper
> > + * bound, not the spec-defined size. Bail if the BAR does not
> have
> > + * room for a full component register block at the recorded
> offset,
> > + * and publish the spec size so the UAPI, sparse-mmap exclusion,
> and
> > + * COMP_REGS region all agree on the same window.
> > + */
> > + if (cxlds->reg_map.max_size < CXL_COMPONENT_REG_BLOCK_SIZE)
> > + return -ENXIO;
>
> This feels like a generic check that should not be vfio specific...
>
> Indeed it is an existing check in cxl_decode_regblock() that already
> makes this assertion.
Agreed - I'll drop the duplicate and rely on cxl-core's existing
assertion in cxl_decode_regblock(), publishing the spec block size from
there rather than re-checking on the vfio side.
>
> > cxl->info.hdm_count = hdm_count;
> > cxl->info.hdm_reg_offset = hdm_off;
> > cxl->info.hdm_reg_size = hdm_size;
> > cxl->info.comp_reg_bir = bir;
> > cxl->info.comp_reg_offset = bar_off;
> > - cxl->info.comp_reg_size = cxlds->reg_map.max_size;
> > + cxl->info.comp_reg_size =
> CXL_COMPONENT_REG_BLOCK_SIZE;
> > cxl->info.host_firmware_committed = true;
> >
> > /*
> > @@ -354,16 +366,515 @@ void vfio_pci_cxl_release(struct
> vfio_pci_core_device *vdev)
> > vdev->cxl = NULL;
> > }
> >
> > +static int vfio_pci_cxl_register_hdm(struct vfio_pci_core_device
> > +*vdev); static int vfio_pci_cxl_register_comp_regs(struct
> > +vfio_pci_core_device *vdev);
> > +
> > int vfio_pci_cxl_open(struct vfio_pci_core_device *vdev) {
> > + struct vfio_pci_cxl_state *cxl = vdev->cxl;
> > + int rc;
> > +
> > + if (!cxl)
> > + return 0; /* plain vfio-pci device */
> > +
> > + rc = vfio_pci_cxl_register_comp_regs(vdev);
> > + if (rc) {
> > + pci_warn(vdev->pdev,
> > + "vfio-cxl: COMP_REGS region register failed
> (%d)\n",
> > + rc);
> > + return rc;
> > + }
> > +
> > + rc = vfio_pci_cxl_register_hdm(vdev);
> > + if (rc) {
> > + pci_warn(vdev->pdev,
> > + "vfio-cxl: HDM region register failed (%d)\n",
> rc);
> > + /*
> > + * COMP_REGS already registered above. vfio core does
> not
> > + * call close_device() when open_device() returns an
> error,
> > + * so roll back the COMP_REGS dynamic region here to
> avoid
> > + * a leaked half-registered open state.
> > + */
> > + vfio_pci_cxl_close(vdev);
> > + return rc;
> > + }
> > + return 0;
> > +}
> > +
> > +void vfio_pci_cxl_close(struct vfio_pci_core_device *vdev) {
> > + struct vfio_pci_cxl_state *cxl = vdev->cxl;
> > + unsigned int i;
> > +
> > + if (!cxl)
> > + return;
> > +
> > + for (i = vdev->num_regions; i > 0; i--) {
> > + struct vfio_pci_region *r = &vdev->region[i - 1];
> > +
> > + if (r->data != cxl)
> > + break;
> > + if (r->ops->release)
> > + r->ops->release(vdev, r);
> > + vdev->num_regions--;
> > + }
> > +}
> > +
> > +/* ------------------------------------------------------------------
> */
> > +/* HDM region: mmappable view of the device's HPA range
> */
> > +/* ------------------------------------------------------------------
> > +*/
> > +
> > +static vm_fault_t hdm_region_fault(struct vm_fault *vmf) {
> > + struct vm_area_struct *vma = vmf->vma;
> > + struct vfio_pci_cxl_state *cxl = vma->vm_private_data;
> > + unsigned long off = (vmf->address - vma->vm_start) +
> > + (vma->vm_pgoff << PAGE_SHIFT);
> > + phys_addr_t pa;
> > +
> > + if (!cxl || !cxl->info.hpa_size)
> > + return VM_FAULT_SIGBUS;
> > + if (off >= cxl->info.hpa_size)
> > + return VM_FAULT_SIGBUS;
> > +
> > + pa = cxl->info.hpa_base + off;
> > + return vmf_insert_pfn(vma, vmf->address, PHYS_PFN(pa));
>
> It seems unfortunate that this reimplements vfio_pci_mmap_ops without
> huge mapping support. If CXL is going to be a first class citizen in
> vfio then why not extend vfio_pci_core_device with the concept that
> devices can have HDM ranges, or some scheme to address large mappings
> from day one.
>
> [..]
> > 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.
> > + */
>
> Rather than working around a problem in the CXL core why not fix it?
> This is the second time someone has run across a conflict with
> devm_cxl_iomap_block() when trying to reuse CXL code.
>
> devm_cxl_iomap_block() was a response to folks wanting /dev/mem access
> to CXL BAR space. When VFIO owns the whole BAR it should be blocking
> /dev/mem access to enforce going through VFIO.
>
> I think this looks like a flag on cxl_register_map that only cxl_pci
> sets to indicate the legacy special mode of doing piecemeal resource
> requests of just the component registers. External CXL drivers likely
> just want to own the whole BAR and not workaround an internal detail
> like this.
okay, I will check this part and handle this in v4 as suggested.