> -----Original Message-----
> From: Alex Williamson <[email protected]>
> Sent: Wednesday, August 26, 2026 4:42 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 05/27] cxl: Add a function-scoped reset entry for vfio-
> pci
>
> External email: Use caution opening links or attachments
>
>
> On Thu, 13 Aug 2026 15:06:09 +0530
> <[email protected]> wrote:
>
> > From: Manish Honap <[email protected]>
> >
> > vfio-pci needs to run a CXL reset on a passthroughed Type-2 device
> > without the host-memory handling in cxl_reset_function(): the memory
> > behind the decoder belongs to the guest.
> >
> > Add cxl_reset_dvsec_sequence(), which runs the DVSEC reset and HDM
> > decoder restore under pci_dev_lock and cxl_rwsem, and
> > cxl_reset_capable() to gate it on a function-scoped reset.
> >
> > Parameterize Memory Clear in cxl_reset_execute() so the guest owns the
> > choice; the host path keeps it disabled.
> >
> > Signed-off-by: Manish Honap <[email protected]>
> > ---
> > drivers/cxl/core/resource.c | 69 ++++++++++++++++++++++++++++++++++-
> --
> > include/cxl/cxl.h | 12 +++++++
> > 2 files changed, 76 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/cxl/core/resource.c b/drivers/cxl/core/resource.c
> > index 492ffe8e3576..cd15bd9171e6 100644
> > --- a/drivers/cxl/core/resource.c
> > +++ b/drivers/cxl/core/resource.c
> > @@ -1164,7 +1164,7 @@ static int cxl_reset_enable_cache(struct pci_dev
> *pdev, int dvsec)
> > PCI_DVSEC_CXL_DISABLE_CACHING); }
> >
> > -static int cxl_reset_initiate(struct pci_dev *pdev, int dvsec)
> > +static int cxl_reset_initiate(struct pci_dev *pdev, int dvsec, bool
> > +mem_clr_en)
> > {
> > u16 ctrl2;
> > int rc;
> > @@ -1173,7 +1173,10 @@ static int cxl_reset_initiate(struct pci_dev *pdev,
> int dvsec)
> > if (rc)
> > return rc;
> >
> > - ctrl2 &= ~PCI_DVSEC_CXL_RST_MEM_CLR_EN;
> > + if (mem_clr_en)
> > + ctrl2 |= PCI_DVSEC_CXL_RST_MEM_CLR_EN;
> > + else
> > + ctrl2 &= ~PCI_DVSEC_CXL_RST_MEM_CLR_EN;
> > ctrl2 |= PCI_DVSEC_CXL_INIT_CXL_RST;
> > return cxl_reset_write_ctrl2(pdev, dvsec, ctrl2); }
>
> I'd again avoid a bool arg here, an enum type might be a better option.
>
> I see in the spec though that CXL Reset Mem Clr Enable is only supported when
> the DVSEC CXL Capability register reports CXL Reset Mem Clr Capable though.
> Should this return -ENOTTY if memory clearing is requested when the device is
> not capable?
okay, agreed; I will return -ENOTTY when a clear is requested but
PCI_DVSEC_CXL_RST_MEM_CLR_CAPABLE is unset
>
> > @@ -1273,7 +1276,7 @@ static int cxl_reset_wait_done(struct pci_dev
> > *pdev, int dvsec, u16 cap) }
> >
> > static int cxl_reset_execute(struct pci_dev *pdev, bool *target_prepared,
> > - int dvsec, u16 cap)
> > + int dvsec, u16 cap, bool mem_clr_en)
> > {
> > int rc, rc2;
> >
> > @@ -1283,7 +1286,7 @@ static int cxl_reset_execute(struct pci_dev
> > *pdev, bool *target_prepared,
> >
> > rc = cxl_pci_target_reset_prepare(pdev, target_prepared);
> > if (!rc)
> > - rc = cxl_reset_initiate(pdev, dvsec);
> > + rc = cxl_reset_initiate(pdev, dvsec, mem_clr_en);
> > if (!rc)
> > rc = cxl_reset_wait_done(pdev, dvsec, cap);
> >
> > @@ -1322,7 +1325,8 @@ int cxl_reset_function(struct pci_dev *pdev, bool
> probe)
> > scoped_guard(rwsem_write, &cxl_rwsem.region) {
> > rc = cxl_hdm_ranges_prepare(&range_ctx, pdev);
> > if (!rc)
> > - rc = cxl_reset_execute(pdev, &target_prepared, dvsec,
> > cap);
> > + rc = cxl_reset_execute(pdev, &target_prepared, dvsec,
> > + cap, false);
> > if (!rc) {
> > u16 command;
> >
> > @@ -1340,3 +1344,58 @@ int cxl_reset_function(struct pci_dev *pdev, bool
> probe)
> > cxl_pci_target_reset_done(pdev, &target_prepared);
> > return rc;
> > }
> > +
> > +/* True when a function-scoped CXL reset is available for @pdev. */
> > +bool cxl_reset_capable(struct pci_dev *pdev) {
> > + u16 cap;
> > +
> > + if (cxl_reset_dvsec(pdev, &cap) < 0)
> > + return false;
> > +
> > + if (pdev->multifunction)
> > + return false;
> > +
> > + return cxl_reset_hdm_available(pdev); }
> > +EXPORT_SYMBOL_NS_GPL(cxl_reset_capable, "CXL");
> > +
> > +/*
> > + * Run the DVSEC reset sequence and restore HDM state for a caller
> > +that owns
> > + * device quiesce and PCI config save/restore, such as vfio-pci. The
> > +HDM range
> > + * collection and CPU cache flush that cxl_reset_function() does for
> > +host-owned
> > + * memory are skipped; that memory belongs to the guest here.
>
> It's worth noting in the comment that a device memory clear without a
> preceding cache invalidation risks that the cache writes back some of the
> memory we just cleared. The use case later in the series does that cache
> invalidation, but the requirement is a bit subtle here. Thanks,
>
I will rebase this onto cxl_reset v11 (cxl_reset_get_dvsec / cxl_reset_execute)
and add
the cache-invalidation-before-clear details in the comment.
Manish
> Alex
>
>
> > + */
> > +int cxl_reset_dvsec_sequence(struct pci_dev *pdev, bool mem_clr_en) {
> > + bool target_prepared = false;
> > + int dvsec;
> > + int rc;
> > + u16 cap;
> > +
> > + dvsec = cxl_reset_dvsec(pdev, &cap);
> > + if (dvsec < 0)
> > + return dvsec;
> > +
> > + if (pdev->multifunction)
> > + return -ENOTTY;
> > +
> > + /*
> > + * Trylock rather than block: This follows the trylock convention of
> > + * pci_reset_bus().
> > + */
> > + if (!pci_dev_trylock(pdev))
> > + return -EBUSY;
> > +
> > + scoped_guard(rwsem_write, &cxl_rwsem.region) {
> > + rc = cxl_reset_execute(pdev, &target_prepared, dvsec, cap,
> > + mem_clr_en);
> > + if (!rc)
> > + rc = cxl_restore_hdm_after_pci_reset(pdev);
> > + }
> > +
> > + cxl_pci_target_reset_done(pdev, &target_prepared);
> > + pci_dev_unlock(pdev);
> > + return rc;
> > +}
> > +EXPORT_SYMBOL_NS_GPL(cxl_reset_dvsec_sequence, "CXL");
> > diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h index
> > f8e8fddba152..541ed6de75a6 100644
> > --- a/include/cxl/cxl.h
> > +++ b/include/cxl/cxl.h
> > @@ -164,6 +164,8 @@ void pci_cxl_hdm_init(struct pci_dev *pdev); void
> > pci_cxl_hdm_release(struct pci_dev *pdev); int
> > cxl_restore_hdm_after_pci_reset(struct pci_dev *pdev); int
> > cxl_reset_function(struct pci_dev *pdev, bool probe);
> > +bool cxl_reset_capable(struct pci_dev *pdev); int
> > +cxl_reset_dvsec_sequence(struct pci_dev *pdev, bool mem_clr_en);
> > #else
> > static inline void pci_cxl_hdm_init(struct pci_dev *pdev) { @@
> > -182,6 +184,16 @@ static inline int cxl_reset_function(struct pci_dev
> > *pdev, bool probe) {
> > return -ENOTTY;
> > }
> > +
> > +static inline bool cxl_reset_capable(struct pci_dev *pdev) {
> > + return false;
> > +}
> > +
> > +static inline int cxl_reset_dvsec_sequence(struct pci_dev *pdev, bool
> > +mem_clr_en) {
> > + return -ENOTTY;
> > +}
> > #endif
> >
> > struct cxl_reg_map {