> -----Original Message-----
> From: Shuai Xue <[email protected]>
> Sent: Thursday, September 3, 2026 5:58 PM
> To: Manish Honap <[email protected]>; [email protected]; [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]
> Cc: 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 v4 17/27] vfio/cxl: Virtualize the CXL DVSEC
> 
> External email: Use caution opening links or attachments
> 
> 
> On 8/13/26 5:36 PM, [email protected] wrote:
> > From: Manish Honap <[email protected]>
> >
> > Serve reads of the CXL DVSEC body from the per-open shadow and keep
> > guest writes in the shadow rather than letting them reach the
> > hardware, so a guest cannot reprogram the device through the DVSEC.
> > Accesses outside the CXL DVSEC return -ENODEV and take the default
> > DVSEC handling, so a device that also exposes a vendor DVSEC is unaffected.
> >
> > Route each shadow write through the CXL r4.0 field class rather than
> > storing it verbatim: Control stays programmable, Status is
> > write-1-to-clear, and Capability, Lock and the Range registers keep
> > their firmware snapshot. The guest can no longer set Config Lock or
> > scribble the capability and range fields.
> >
> > Signed-off-by: Manish Honap <[email protected]>
> > ---
> >   drivers/vfio/pci/cxl/vfio_cxl_core.c | 88
> ++++++++++++++++++++++++++++
> >   drivers/vfio/pci/vfio_pci_config.c   | 36 +++++++++++-
> >   include/linux/vfio_pci_core.h        |  5 ++
> >   include/uapi/linux/pci_regs.h        |  1 +
> >   4 files changed, 129 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > b/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > index 2e516a0929c6..9fed909cb9d3 100644
> > --- a/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > +++ b/drivers/vfio/pci/cxl/vfio_cxl_core.c
> > @@ -148,11 +148,99 @@ static void vfio_cxl_close_device(struct
> vfio_pci_core_device *vdev)
> >       cxl->dvsec_shadow = NULL;
> >   }
> >
> > +/* Read a 16-bit DVSEC field from the shadow; @off is DVSEC-relative.
> > +*/ static u16 vfio_cxl_dvsec16(struct vfio_cxl_state *cxl, u32 off) {
> > +     u32 dw = cxl->dvsec_shadow[off / sizeof(u32)];
> > +
> > +     return (dw >> (8 * (off % sizeof(u32)))) & 0xffff; }
> > +
> > +/*
> > + * Apply the CXL r4.0 8.1.3 write class for the 16-bit DVSEC register at 
> > @off.
> > + * Control is programmable, Status is write-1-to-clear, and
> > +Capability, Lock and
> > + * the Range registers stay fixed at their firmware snapshot.
> > + */
> > +static u16 vfio_cxl_dvsec_field(u32 off, u16 old, u16 wval, u16
> > +wmask) {
> > +     switch (off) {
> > +     case PCI_DVSEC_CXL_CTRL:
> > +             /*
> > +              * CXL.mem stays enabled for as long as the guest owns the 
> > device.
> > +              * The HDM decoder maps the guest window to device memory, so 
> > a
> > +              * store to it while CXL.mem is disabled completes on the 
> > device as
> > +              * an error that the host fabric reports as an SError, which 
> > is
> > +              * fatal. The spec does not pin down accesses to a decoder 
> > whose
> > +              * CXL.mem is off and many hosts SError, so ignore a guest 
> > request
> > +              * to clear the enable and keep the bit set.
> > +              */
> > +             return ((old & ~wmask) | (wval & wmask)) |
> PCI_DVSEC_CXL_MEM_ENABLE;
> > +     case PCI_DVSEC_CXL_CTRL2:
> > +             return (old & ~wmask) | (wval & wmask);
> 
> 
> Control2 is routed through the r4.0 write class as plain RW, but both INITIATE
> bits are self-clearing doorbells per spec: the guest sets the bit, the device
> performs the operation and clears it, and completion is observed in STATUS2
> (Cache_Invalid for the WBI). With the plain-RW class the shadow latches the
> bit at 1 forever, and because reads are served from the open-time snapshot,
> Cache_Invalid
> (CXL_DVSEC_STATUS2_CACHE_INVALID) never changes either.
> Both polling paths are dead ends.
> 
> The interesting part is that the series already models this correctly for the
> sibling command bit -- the vfio_cxl_reset() epilogue does:
> 
>         /*
>          * The guest-facing DVSEC bookkeeping only applies while the device
>          * is open. Initiate_CXL_Reset self-clears in hardware; mirror that
>          * and stamp the outcome onto a fresh hardware STATUS2 read for the
>          * polling guest.
>          */
> 
> INIT_CXL_RST is self-cleared in the shadow and the outcome is stamped into
> STATUS2 for the polling guest. Initiate_Cache_WBI just never gets the same
> treatment.
> 
> The polling contract is one this series itself implements on the host
> side: cxl_reset_wait_cache_wbi() sets WBI, then polls STATUS2 Cache_Invalid
> with a 100ms budget. A guest kernel running the same sequence would set
> WBI, poll the frozen snapshot, and time out before ever reaching
> INIT_CXL_RST, so whether a guest-initiated CXL reset succeeds depends on the
> open-time STATUS2 value rather than on device state. The stuck command bit
> is also directly visible to any guest reading CTRL2 back.
> 
> Would the minimal fix be to mirror the epilogue's INIT_CXL_RST handling for
> WBI: self-clear the bit on the 0->1 write and set Cache_Invalid in the shadow
> (the host already runs the real WBI at VM power on/off via
> cxl_reset_dvsec_sequence(), and the existing W1C class on STATUS2 lets the
> guest clear Cache_Invalid before the next round)? Or is forwarding the WBI to
> hardware and keeping Cache_Invalid live the intended long-term model?
> 
> Thanks.
> Shuai

Your minimal fix is the intended model, and it cleanly fits the
vfio_pci_config.c rework which Alex suggested.  Control2 becomes a cxl_perms
write handler (the way msi_perms uses vfio_msi_config_write), and on the guest
0->1 write it self-clears the Initiate bit and stamps STATUS2.Cache_Invalid in
vconfig as a side effect, the same self-clear-and-stamp the reset path applies
to Initiate_CXL_Reset. (WBI will not be forwarded to hardware. The real
write-back and invalidate runs host-side in cxl_reset_dvsec_sequence() at the
reset boundary)

Thanks,
Manish

Reply via email to