> -----Original Message----- > From: Alex Williamson <[email protected]> > Sent: Thursday, August 27, 2026 3:47 AM > To: Manish Honap <[email protected]> > Cc: [email protected]; Ankit Agrawal <[email protected]>; [email protected]; > [email protected]; [email protected]; Srirangan Madhavan > <[email protected]>; [email protected]; [email protected]; > [email protected]; [email protected]; [email protected]; > [email protected]; [email protected]; Yishai Hadas > <[email protected]>; Shameer Kolothum Thodi > <[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]>; linux- > [email protected]; [email protected]; [email protected]; > [email protected]; [email protected]; linux- > [email protected]; [email protected]; [email protected] > Subject: Re: [PATCH v4 07/27] vfio/pci: Detect CXL devices and load vfio-cxl > on > demand > > External email: Use caution opening links or attachments > > > On Thu, 13 Aug 2026 15:06:11 +0530 > <[email protected]> wrote: > > > From: Manish Honap <[email protected]> > > > > A CXL device needs the vfio-cxl callbacks, but pulling vfio-cxl and > > the CXL core in unconditionally would bloat every vfio-pci setup. At > > bind, detect a CXL device with pcie_is_cxl() and > > request_module("vfio-cxl") only then, and hand the device to the registered > ops. > > > > Each bound CXL device pins vfio-cxl through try_module_get() and drops > > the reference at release, so vfio-cxl can unload once no CXL device is > > bound. If vfio-cxl is absent the device is driven as plain vfio-pci. > > > > Signed-off-by: Manish Honap <[email protected]> > > --- > > drivers/vfio/pci/vfio_pci_core.c | 81 ++++++++++++++++++++++++++++++-- > > include/linux/vfio_pci_core.h | 3 ++ > > 2 files changed, 81 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/vfio/pci/vfio_pci_core.c > > b/drivers/vfio/pci/vfio_pci_core.c > > index 88e68d43af9a..0f9b5dfeea66 100644 > > --- a/drivers/vfio/pci/vfio_pci_core.c > > +++ b/drivers/vfio/pci/vfio_pci_core.c > > @@ -2176,6 +2176,44 @@ static void vfio_pci_vga_uninit(struct > vfio_pci_core_device *vdev) > > VGA_RSRC_LEGACY_MEM); } > > > > +static const struct vfio_cxl_ops *vfio_pci_cxl_ops; static > > +DEFINE_MUTEX(vfio_pci_cxl_ops_lock); > > + > > +static const struct vfio_cxl_ops *vfio_pci_get_cxl_ops(void) { > > + const struct vfio_cxl_ops *ops; > > + > > + mutex_lock(&vfio_pci_cxl_ops_lock); > > + ops = vfio_pci_cxl_ops; > > + if (ops && !try_module_get(ops->owner)) > > + ops = NULL; > > + mutex_unlock(&vfio_pci_cxl_ops_lock); > > + > > + return ops; > > +} > > Awkward flow, resolved with guards: > > guard(rwsem_read)(&vfio_pci_cxl_ops_lock); > ops = vfio_pci_cxl_ops; > if (!ops || !try_module_get(ops->owner)) > return NULL; > > return ops; > Okay, I will update this. > > + > > +/* > > + * A CXL Type-2 device advertises both CXL.cache and CXL.mem in its CXL > DVSEC. > > + * pcie_is_cxl() is also true for Type-1 (cache only) and Type-3 (mem > > +only) > > + * devices, which the vfio-cxl provider does not handle, so confirm > > +the Type-2 > > + * identity before engaging it. > > + */ > > +static bool vfio_pci_is_cxl_type2(struct pci_dev *pdev) { > > + u16 dvsec, cap; > > + > > + dvsec = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL, > > + PCI_DVSEC_CXL_DEVICE); > > + if (!dvsec) > > + return false; > > + > > + if (pci_read_config_word(pdev, dvsec + PCI_DVSEC_CXL_CAP, &cap)) > > + return false; > > + > > + return (cap & PCI_DVSEC_CXL_CACHE_CAPABLE) && > > + (cap & PCI_DVSEC_CXL_MEM_CAPABLE); } > > + > > int vfio_pci_core_init_dev(struct vfio_device *core_vdev) { > > struct vfio_pci_core_device *vdev = @@ -2197,6 +2235,41 @@ int > > vfio_pci_core_init_dev(struct vfio_device *core_vdev) > > init_rwsem(&vdev->memory_lock); > > xa_init(&vdev->ctx); > > > > + /* > > + * Load vfio-cxl on demand for a CXL device. If it is absent, drive > > the > > + * device as plain vfio-pci rather than failing the bind. > > + */ > > + if (pcie_is_cxl(vdev->pdev) && > > + vfio_pci_is_cxl_type2(vdev->pdev)) { > > Nit, embed the pcie_is_cxl() test in vfio_pci_is_cxl_type2(). Okay, I will fold pcie_is_cxl() into vfio_pci_is_cxl_type2(). > > > + const struct vfio_cxl_ops *ops; > > + > > + request_module("vfio-cxl"); > > + ops = vfio_pci_get_cxl_ops(); > > + if (ops) { > > + ret = ops->init_device(vdev); > > + if (ret) { > > + module_put(ops->owner); > > Create a trivial vfio_pci_put_cxl_ops() for consistency. Okay. > > > + return ret; > > This looks like a regression, a device that previously worked with vfio-pci > now > fails if vfio-cxl .init returns an error. It should continue with a log > message. Agreed. I will modify this so that the CXL init failure becomes non-fatal I will log the failure, drop module ref and continue as plain vfio-pci in this case) > > The disable_cxl option that comes later is a global opt-out, not an opt-in. > Users > can opt-in to a feature that might fail previous behavior but they should not > be > required to opt-out to retain existing functionality, especially with only > global > granularity. Okay, I will make sure the opt-out no longer gates the fallback. > > > + } > > + vdev->cxl_ops = ops; > > + /* > > + * Pin the device in D0 while bound rather than let > > + * the host power it down between opens. > > + */ > > + vdev->disable_idle_d3 = true; > > Why? Letting the host power down the device between opens is exactly what > we want for non-cxl devices. If we're trying to do something around > preserving > the coherent memory configuration, it needs to be justified as such, and > should > happen at the point where it's relevant, ie. in the vfio-cxl .init path. > > However, this alone doesn't prevent the user from using low power states, so > it > also seems insufficient by itself. I will Move disable_idle_d3 into the CXL .init path with the justification added there and for this series, add the full guest-D3 block in the cover-letter as a follow-up item. > > > + } else if (IS_BUILTIN(CONFIG_VFIO_CXL)) { > > + /* > > + * Only DEFER for a built-in provider so the bind > > + * retries once vfio-cxl registers its ops. > > + * A modular provider was already loaded synchronously > > + * by request_module() above, so if it is still absent > > + * it is missing, blocked, or failed to init; drive > > the > > + * device as plain vfio-pci then rather than defer the > > + * bind forever. > > + */ > > + return -EPROBE_DEFER; > > LLM asks if the registration function should call > driver_deferred_probe_trigger() to make the retry explicit? Okay, I will add a call to driver_deferred_probe_trigger() from register. > > > + } > > + } > > + > > return 0; > > } > > EXPORT_SYMBOL_GPL(vfio_pci_core_init_dev); > > @@ -2206,6 +2279,11 @@ void vfio_pci_core_release_dev(struct > vfio_device *core_vdev) > > struct vfio_pci_core_device *vdev = > > container_of(core_vdev, struct vfio_pci_core_device, > > vdev); > > > > + if (vdev->cxl_ops) { > > + vdev->cxl_ops->release_device(vdev); > > + module_put(vdev->cxl_ops->owner); > > + } > > Turn both of these into helpers: > > static int vfio_pci_core_cxl_init(struct vfio_device *core_vdev); static void > vfio_pci_core_cxl_release(struct vfio_device *core_vdev); > > Include the tests is-cxl/cxl_ops tests in the helpers to compartmentalize cxl > init/release. Thanks, Okay. Manish > > Alex > > > + > > mutex_destroy(&vdev->igate); > > mutex_destroy(&vdev->ioeventfds_lock); > > kfree(vdev->region); > > @@ -2670,9 +2748,6 @@ static void vfio_pci_dev_set_try_reset(struct > vfio_device_set *dev_set) > > } > > } > > > > -static const struct vfio_cxl_ops *vfio_pci_cxl_ops; -static > > DEFINE_MUTEX(vfio_pci_cxl_ops_lock); > > - > > int vfio_pci_core_register_cxl_ops(const struct vfio_cxl_ops *ops) { > > int ret = 0; > > diff --git a/include/linux/vfio_pci_core.h > > b/include/linux/vfio_pci_core.h index 14753972e714..117cd67995d8 > > 100644 > > --- a/include/linux/vfio_pci_core.h > > +++ b/include/linux/vfio_pci_core.h > > @@ -29,6 +29,7 @@ struct vfio_pci_core_device; struct > > vfio_pci_region; struct p2pdma_provider; struct dma_buf_attachment; > > +struct vfio_cxl_state; > > > > struct vfio_pci_eventfd { > > struct eventfd_ctx *ctx; > > @@ -109,6 +110,8 @@ struct vfio_pci_core_device { > > struct vfio_device vdev; > > struct pci_dev *pdev; > > const struct vfio_pci_device_ops *pci_ops; > > + const struct vfio_cxl_ops *cxl_ops; > > + struct vfio_cxl_state *cxl; > > void __iomem *barmap[PCI_STD_NUM_BARS]; > > bool bar_mmap_supported[PCI_STD_NUM_BARS]; > > /* Flags modified at runtime - dedicated storage unit */

