> -----Original Message-----
> From: Jonathan Cameron <[email protected]>
> Sent: Saturday, September 26, 2026 3:53 AM
> To: Manish Honap <[email protected]>
> Cc: [email protected]; [email protected]; Ankit Agrawal <[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]
> Subject: Re: [PATCH v5 16/27] vfio/cxl: Create the CXL memdev and set media
> ready at bind
> 
> External email: Use caution opening links or attachments
> 
> 
> On Thu, 17 Sep 2026 00:05:29 +0530
> <[email protected]> wrote:
> 
> > From: Manish Honap <[email protected]>
> >
> > At bind, build the CXL memory device for the passed-through Type-2
> > accelerator so it joins the CXL topology and its HDM region resolves
> > to a host physical range. A Type-2 device has no mailbox, so there is
> > no media-ready register to poll: set media ready directly once the
> > component registers validate (mirroring
> > drivers/net/ethernet/sfc/efx_cxl.c)
> >
> > As per current vfio-cxl support, reject a device with:
> > - more than one HDM decoder
> > - interleaving enabled
> > - whose reset the host cannot service
> >
> > The CXL-core allocations are grouped with devres so a failed bind
> > unwinds
> > them: init failure falls back to plain vfio-pci with the device still
> > bound, so devm would otherwise hold them until unbind.
> >
> > A low-power transition would reset the CXL Type-2 function and lose
> > its CXL.mem contents, so keep it in D0 while it is assigned.
> >
> > Assisted-by: LLM
> > Signed-off-by: Manish Honap <[email protected]>
> A small thing inline.
> 
> > ---
> >  drivers/vfio/pci/cxl/vfio_cxl_core.c | 118
> +++++++++++++++++++++++++++
> >  drivers/vfio/pci/vfio_pci_core.c     |  16 ++++
> >  2 files changed, 134 insertions(+)
> >
> > diff --git a/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > b/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > index cd5d41856404..0d92e6a409c1 100644
> > --- a/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > +++ b/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > @@ -6,15 +6,132 @@
> >   */
> >
> >  #include <linux/module.h>
> > +#include <linux/pci.h>
> > +#include <linux/range.h>
> >  #include <linux/vfio_pci_core.h>
> > +#include <cxl/cxl.h>
> > +#include <cxl/pci.h>
> > +
> > +/**
> > + * struct vfio_cxl_state - per-device state for a vfio-cxl device
> > + * @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  */ struct
> > +vfio_cxl_state {
> > +     struct cxl_dev_state cxlds;
> > +     struct cxl_memdev *cxlmd;
> > +     struct range hpa_range;
> > +};
> >
> >  static int vfio_cxl_init_device(struct vfio_pci_core_device *vdev)  {
> > +     struct pci_dev *pdev = vdev->pdev;
> > +     struct vfio_cxl_state *cxl;
> > +     struct cxl_memdev *cxlmd;
> > +     u64 hdm_size, serial;
> > +     u16 dvsec;
> > +     int ret;
> > +
> > +     /*
> > +      * pdev->hdm is cached at PCI enumeration, before any driver binds, 
> > so a
> > +      * device without it has no usable HDM decoder. Fall back to plain
> > +      * vfio-pci rather than deferring the bind forever.
> > +      */
> > +     if (!pdev->hdm)
> > +             return -ENODEV;
> > +
> > +     /* The guest drives one virtual decoder; multiple are unsupported. */
> > +     if (pdev->hdm->decoder_count != 1)
> > +             return -EOPNOTSUPP;
> > +
> > +     /* An interleaved decoder cannot be mapped 1:1 to the guest. */
> > +     if (pdev->hdm->settings[0].interleave_ways != 1)
> > +             return -EOPNOTSUPP;
> > +
> > +     /*
> > +      * The guest drives resets through the CXL Device DVSEC and polls the
> > +      * shadow for completion. If the host cannot service a function-scoped
> > +      * CXL reset, that request could never complete, so refuse the device
> > +      * rather than advertise a reset the guest would poll on forever.
> > +      */
> > +     if (!cxl_reset_capable(pdev))
> > +             return -EOPNOTSUPP;
> > +
> > +     hdm_size = range_len(&pdev->hdm->settings[0].hpa_range);
> > +     if (!hdm_size)
> > +             return -ENXIO;
> > +
> > +     dvsec = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL,
> > +                                       PCI_DVSEC_CXL_DEVICE);
> > +     serial = pci_get_dsn(pdev);
> > +
> > +     /*
> > +      * Group the CXL-core allocations so a later failure unwinds them 
> > here.
> > +      * A failed init falls back to plain vfio-pci with the device still
> > +      * bound, so devm would otherwise hold them until unbind.
> > +      */
> > +     if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
> > +             return -ENOMEM;
> > +
> 
> I'd be tempted to factor out the stuff that is unwound via the group. If this
> were simple a call to a helper function, that helper could return directly on
> error giving us simpler code flow.  Then you'd just check the helper return to
> find out if you should close or release the group.

Okay, agreed.

I will move the memdev setup into a helper that returns on the first error, and 
the
caller closes the group on success or releases it on failure.

> 
> > +     cxl = devm_cxl_dev_state_create(&pdev->dev, CXL_DEVTYPE_DEVMEM,
> serial,
> > +                                     dvsec, struct vfio_cxl_state, cxlds,
> > +                                     false);
> > +     if (!cxl) {
> > +             ret = -ENOMEM;
> > +             goto err;
> > +     }
> > +
> > +     ret = cxl_pci_setup_regs(pdev, CXL_REGLOC_RBI_COMPONENT,
> > +                              &cxl->cxlds.reg_map);
> > +     if (ret) {
> > +             pci_err(pdev, "vfio-cxl: no component registers\n");
> > +             goto err;
> > +     }
> > +
> > +     if (!cxl->cxlds.reg_map.component_map.hdm_decoder.valid) {
> > +             pci_err(pdev, "vfio-cxl: HDM decoder registers not found\n");
> > +             ret = -ENODEV;
> > +             goto err;
> > +     }
> > +
> > +     /*
> > +      * A Type-2 accelerator has no mailbox and no media-ready register, so
> > +      * set media ready directly.
> > +      */
> > +     cxl->cxlds.media_ready = true;
> > +
> > +     ret = cxl_set_capacity(&cxl->cxlds, hdm_size);
> > +     if (ret)
> > +             goto err;
> > +
> > +     cxlmd = devm_cxl_probe_mem(&cxl->cxlds, &cxl->hpa_range);
> > +     if (IS_ERR(cxlmd)) {
> > +             ret = PTR_ERR(cxlmd);
> > +             goto err;
> > +     }
> > +
> > +     cxl->cxlmd = cxlmd;
> > +     devres_close_group(&pdev->dev, NULL);
> > +
> > +     /*
> > +      * Powering a CXL Type-2 function down and back up reinitializes its
> > +      * device state and discards the contents of its coherent memory. Pin
> > +      * it in D0 for as long as it is assigned so CXL.mem stays intact.
> > +      */
> > +     vdev->disable_idle_d3 = true;
> > +     vdev->cxl = cxl;
> > +
> >       return 0;
> > +
> > +err:
> > +     devres_release_group(&pdev->dev, NULL);
> > +     return ret;
> >  }
> >
> >  static void vfio_cxl_release_device(struct vfio_pci_core_device
> > *vdev)  {
> > +     vdev->cxl = NULL;
> >  }
> >
> >  static int vfio_cxl_open_device(struct vfio_pci_core_device *vdev) @@
> > -59,3 +176,4 @@ module_exit(vfio_cxl_exit);
> >
> >  MODULE_LICENSE("GPL");
> >  MODULE_DESCRIPTION("VFIO support for CXL Type-2 devices");
> > +MODULE_IMPORT_NS("CXL");

Reply via email to