From: <mhonap@nvidia.com>
To: <alex@shazbot.org>, <jgg@ziepe.ca>, <ankita@nvidia.com>,
<jic23@kernel.org>, <dave.jiang@intel.com>,
<alejandro.lucero-palau@amd.com>, <smadhavan@nvidia.com>,
<corbet@lwn.net>, <skhan@linuxfoundation.org>,
<dave@stgolabs.net>, <alison.schofield@intel.com>,
<vishal.l.verma@intel.com>, <iweiny@kernel.org>,
<ming.li@zohomail.com>, <yishaih@nvidia.com>,
<skolothumtho@nvidia.com>, <kevin.tian@intel.com>,
<bhelgaas@google.com>, <dmatlack@google.com>, <kees@kernel.org>,
<gustavoars@kernel.org>
Cc: <cjia@nvidia.com>, <kjaju@nvidia.com>, <vsethi@nvidia.com>,
<zhiw@nvidia.com>, <mhonap@nvidia.com>,
<linux-doc@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<kvm@vger.kernel.org>, <linux-cxl@vger.kernel.org>,
<linux-pci@vger.kernel.org>, <linux-kselftest@vger.kernel.org>,
<linux-hardening@vger.kernel.org>
Subject: [PATCH v6 29/31] vfio/cxl: Run the CXL reset at the vfio reset points
Date: Fri, 16 Oct 2026 21:48:36 +0530 [thread overview]
Message-ID: <20261016161839.2765592-30-mhonap@nvidia.com> (raw)
In-Reply-To: <20261016161839.2765592-1-mhonap@nvidia.com>
From: Manish Honap <mhonap@nvidia.com>
A CXL Type-2 function must not take an FLR in place of CXL Reset: an FLR
leaves CXL.cache and CXL.mem state, the CXL DVSEC and the HDM contents
untouched (CXL r4.0 sec 9.5), so device memory and cache would carry one
user's data to the next. CXL Reset resets that state as well (sec 9.7).
The PCI core orders cxl_reset ahead of flr in pci_reset_fn_methods[],
but falls through to FLR when cxl_reset returns -ENOTTY.
vfio-pci-core routes its reset points through the provider reset op. In
vfio-cxl that op runs pci_cxl_reset_owned() with the HDM range claim.
The reset resets the function, clearing or randomizing volatile device
memory, and restores the HDM decoder and PCI config state, so it is a
complete replacement for pci_try_reset_function() on a CXL device. The
op runs with memory_lock and the PCI device lock held.
Take the HDM memory region out of use for the duration of the reset, so
a fault cannot insert a PFN into a decoder that is being torn down, and
put it back only once the reset has restored the decoder and the device
reports its memory active again. After CXL Reset with Memory Clear the
device can keep Memory_Active clear for seconds (about 3 s on the device
this was tested on), and a host access to the HDM range in that window
raised an SError. A reset whose memory does not come back within the
Memory_Active_Timeout fails like any other. A failed reset
returns its error and leaves the region out of use until a later CXL
Reset succeeds. Neither a decoder restore after low power nor a hot
reset reopens it in between, since device memory may still hold data the
reset was meant to clear. If a failed reset left CXL.cache or CXL.mem
disabled in the DVSEC Control register, which makes cxl_reset refuse the
device, put back the Control value taken at bind before the next reset.
A failed reset leaves Memory Space disabled; clear vfio-pci-core's
record of it to match. AER recovery does not reopen HDM after a failed
CXL Reset either.
Assisted-by: LLM
Signed-off-by: Manish Honap <mhonap@nvidia.com>
---
drivers/vfio/pci/cxl/vfio_cxl_core.c | 82 ++++++++++++++++++++++++++--
1 file changed, 77 insertions(+), 5 deletions(-)
diff --git a/drivers/vfio/pci/cxl/vfio_cxl_core.c b/drivers/vfio/pci/cxl/vfio_cxl_core.c
index 518f0b093652..70794efd517b 100644
--- a/drivers/vfio/pci/cxl/vfio_cxl_core.c
+++ b/drivers/vfio/pci/cxl/vfio_cxl_core.c
@@ -38,6 +38,8 @@
* for Memory_Active before host access reopens after a reset or low power
* @mem_region_index: vfio region index of the HDM memory region while open, else 0
* @hdm_open_at_prepare: @hdm_valid as reset_prepare found it; under memory_lock
+ * @hdm_needs_reset: a CXL Reset failed, so only a CXL Reset that succeeds
+ * reopens host access; under memory_lock
*/
struct vfio_cxl_state {
struct cxl_dev_state cxlds;
@@ -52,6 +54,7 @@ struct vfio_cxl_state {
bool await_mem_active;
unsigned int mem_region_index;
bool hdm_open_at_prepare;
+ bool hdm_needs_reset;
};
static unsigned long vfio_cxl_mem_pgoff(struct vm_area_struct *vma,
@@ -827,17 +830,75 @@ static void vfio_cxl_sync_mem_enable(struct vfio_pci_core_device *vdev)
}
/*
- * vfio-cxl holds the HDM range, so the PCI core's cxl_reset method would
- * fail to request it. Run the same CXL Reset with that claim.
+ * cxl_reset refuses a device whose CXL DVSEC Control has Cache_Enable or
+ * Mem_Enable clear (-ENOTTY). A CXL Reset that failed after the device reset
+ * may leave Control at its reset value, so every later reset would refuse and
+ * host access would never reopen. Put back the Control value taken at bind,
+ * when pci_cxl_reset_capable() required both enables, before the reset.
+ */
+static void vfio_cxl_restore_dvsec_ctrl(struct vfio_pci_core_device *vdev)
+{
+ const u16 enables = PCI_DVSEC_CXL_CACHE_ENABLE | PCI_DVSEC_CXL_MEM_ENABLE;
+ const struct cxl_hdm_info *hdm = vdev->cxl->hdm;
+ struct pci_dev *pdev = vdev->pdev;
+ u16 ctrl;
+
+ if (!hdm->dvsec_ctrl_valid || (hdm->dvsec_ctrl & enables) != enables)
+ return;
+
+ if (pci_read_config_word(pdev, hdm->dvsec + PCI_DVSEC_CXL_CTRL, &ctrl) ||
+ PCI_POSSIBLE_ERROR(ctrl) || (ctrl & enables) == enables)
+ return;
+
+ pci_warn(pdev, "vfio-cxl: restoring CXL DVSEC control %#06x (was %#06x)\n",
+ hdm->dvsec_ctrl, ctrl);
+ pci_write_config_word(pdev, hdm->dvsec + PCI_DVSEC_CXL_CTRL,
+ hdm->dvsec_ctrl);
+}
+
+/*
+ * Run CXL Reset in place of a PCI function reset. An FLR leaves CXL.mem
+ * state and HDM contents intact (CXL r4.0 sec 9.5), so the vfio reset points
+ * route here. The reset clears or randomizes volatile device memory and
+ * restores the HDM decoder. The caller holds memory_lock and the PCI device
+ * lock. vfio-cxl holds the HDM range, so the PCI core's cxl_reset method
+ * would fail to request it; run the same CXL Reset with that claim.
*/
static int vfio_cxl_reset(struct vfio_pci_core_device *vdev)
{
+ struct pci_dev *pdev = vdev->pdev;
+ int ret;
+
+ /* Host CPU access to the HDM range is unsafe until the decoder is back. */
+ vfio_cxl_revoke_hdm(vdev);
+
+ /* Only after a failure: see vfio_cxl_restore_dvsec_ctrl(). */
+ if (vdev->cxl->hdm_needs_reset)
+ vfio_cxl_restore_dvsec_ctrl(vdev);
+
/*
* The reset restores PCI state from the saved copy. The caller provides
* it: the try-reset helper saves the current state, and the close path
* keeps the open-time state that vfio_pci_core_disable() loaded.
*/
- return pci_cxl_reset_owned(vdev->pdev, vdev->cxl->hpa_res);
+ ret = pci_cxl_reset_owned(pdev, vdev->cxl->hpa_res);
+ if (!ret)
+ ret = vfio_cxl_await_mem_active(vdev);
+ if (ret) {
+ /*
+ * Device memory may hold data the reset was meant to clear. Only
+ * a later CXL Reset that succeeds reopens host access; a decoder
+ * restore alone does not.
+ */
+ vdev->cxl->hdm_needs_reset = true;
+ vfio_cxl_sync_mem_enable(vdev);
+ return ret;
+ }
+
+ vdev->cxl->hdm_needs_reset = false;
+ vfio_cxl_rearm_hdm(vdev);
+
+ return 0;
}
/*
@@ -881,6 +942,10 @@ static void vfio_cxl_power_up(struct vfio_pci_core_device *vdev)
lockdep_assert_held_write(&vdev->memory_lock);
+ /* After a failed CXL Reset, only a CXL Reset reopens host access. */
+ if (cxl->hdm_needs_reset)
+ return;
+
/*
* A D3 request that failed, or a quirk that kept the device in D0,
* lost nothing: reopen without decommitting and recommitting.
@@ -984,6 +1049,10 @@ static int vfio_cxl_reset_done(struct vfio_pci_core_device *vdev)
return 0;
}
+ /* After a failed CXL Reset, only a CXL Reset reopens host access. */
+ if (cxl->hdm_needs_reset)
+ return 0;
+
ret = vfio_cxl_await_mem_active(vdev);
if (ret)
return ret;
@@ -1007,8 +1076,11 @@ static void vfio_cxl_error_resume(struct vfio_pci_core_device *vdev)
if (pdev->current_state != PCI_D0)
return;
- /* The region was closed before the error; keep it that way. */
- if (!vdev->cxl->hdm_open_at_prepare)
+ /*
+ * The region was closed before the error, or a CXL Reset failed while
+ * recovery ran; keep it closed until a CXL Reset succeeds.
+ */
+ if (!vdev->cxl->hdm_open_at_prepare || vdev->cxl->hdm_needs_reset)
return;
if (!vfio_cxl_hdm_intact(vdev)) {
--
2.53.0
next prev parent reply other threads:[~2026-10-16 16:23 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-16 16:18 [PATCH v6 00/31] vfio/pci: Add CXL Type-2 device passthrough support mhonap
2026-10-16 16:18 ` [PATCH v6 01/31] cxl/regs: Split the BAR block request and ioremap helpers mhonap
2026-10-16 16:18 ` [PATCH v6 02/31] cxl/regs: Let a BAR-owning driver own the component register block mhonap
2026-10-16 16:18 ` [PATCH v6 03/31] cxl: Move component register defines to uapi/cxl/cxl_regs.h mhonap
2026-10-16 16:18 ` [PATCH v6 04/31] PCI/CXL: Let the driver that owns the HDM range run CXL Reset mhonap
2026-10-16 16:18 ` [PATCH v6 05/31] PCI: Refuse bus and slot reset below a CXL port with SBR masked mhonap
2026-10-16 16:18 ` [PATCH v6 06/31] vfio/pci: Add the CXL provider ops registration interface mhonap
2026-10-16 16:18 ` [PATCH v6 07/31] vfio/pci: Detect CXL devices and load the CXL provider on demand mhonap
2026-10-16 16:18 ` [PATCH v6 08/31] vfio/pci: Add a generic excluded-range list mhonap
2026-10-16 16:18 ` [PATCH v6 09/31] vfio/pci: Advertise the mmap areas around excluded ranges mhonap
2026-10-16 16:18 ` [PATCH v6 10/31] vfio/pci: Refuse ioeventfds and dma-buf exports over " mhonap
2026-10-16 16:18 ` [PATCH v6 11/31] vfio/pci: Virtualize the CXL DVSEC in vfio_pci_config.c mhonap
2026-10-16 16:18 ` [PATCH v6 12/31] vfio/pci: Call the CXL open and close hooks around device use mhonap
2026-10-16 16:18 ` [PATCH v6 13/31] vfio/pci: Bracket PCI resets with the CXL reset hooks mhonap
2026-10-16 16:18 ` [PATCH v6 14/31] vfio/pci: Provide an opt-out for the CXL Type-2 extensions mhonap
2026-10-16 16:18 ` [PATCH v6 15/31] vfio/pci: Route every reset point through a try-reset helper mhonap
2026-10-16 16:18 ` [PATCH v6 16/31] vfio/pci: Revoke and re-arm one device-specific region mhonap
2026-10-16 16:18 ` [PATCH v6 17/31] vfio/pci: Call the device provider across low-power transitions mhonap
2026-10-16 16:18 ` [PATCH v6 18/31] vfio/cxl: Add the vfio-cxl provider module skeleton mhonap
2026-10-16 16:18 ` [PATCH v6 19/31] vfio/cxl: Create the CXL memdev and set media ready at bind mhonap
2026-10-16 16:18 ` [PATCH v6 20/31] vfio/cxl: Own the whole component register BAR mhonap
2026-10-16 16:18 ` [PATCH v6 21/31] vfio/cxl: Expose the HDM memory region to the guest mhonap
2026-10-16 16:18 ` [PATCH v6 22/31] vfio/cxl: Allow mmap of the HDM memory region mhonap
2026-10-16 16:18 ` [PATCH v6 23/31] vfio/cxl: Contain HDM memory errors with memory_failure() mhonap
2026-10-16 16:18 ` [PATCH v6 24/31] vfio/cxl: Expose the HDM decoder registers read-only to the guest mhonap
2026-10-16 16:18 ` [PATCH v6 25/31] vfio/cxl: Exclude the HDM decoder registers from direct BAR access mhonap
2026-10-16 16:18 ` [PATCH v6 26/31] vfio/cxl: Restore the HDM decoder after a hot reset mhonap
2026-10-16 16:18 ` [PATCH v6 27/31] vfio/cxl: Describe the CXL device and decoder geometry to userspace mhonap
2026-10-16 16:18 ` [PATCH v6 28/31] vfio/cxl: Export the HDM memory region as a dma-buf mhonap
2026-10-16 16:18 ` mhonap [this message]
2026-10-16 16:18 ` [PATCH v6 30/31] Documentation: vfio-pci: Document CXL Type-2 device passthrough mhonap
2026-10-16 16:18 ` [PATCH v6 31/31] selftests/vfio: Add CXL Type-2 passthrough tests mhonap
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261016161839.2765592-30-mhonap@nvidia.com \
--to=mhonap@nvidia.com \
--cc=alejandro.lucero-palau@amd.com \
--cc=alex@shazbot.org \
--cc=alison.schofield@intel.com \
--cc=ankita@nvidia.com \
--cc=bhelgaas@google.com \
--cc=cjia@nvidia.com \
--cc=corbet@lwn.net \
--cc=dave.jiang@intel.com \
--cc=dave@stgolabs.net \
--cc=dmatlack@google.com \
--cc=gustavoars@kernel.org \
--cc=iweiny@kernel.org \
--cc=jgg@ziepe.ca \
--cc=jic23@kernel.org \
--cc=kees@kernel.org \
--cc=kevin.tian@intel.com \
--cc=kjaju@nvidia.com \
--cc=kvm@vger.kernel.org \
--cc=linux-cxl@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=ming.li@zohomail.com \
--cc=skhan@linuxfoundation.org \
--cc=skolothumtho@nvidia.com \
--cc=smadhavan@nvidia.com \
--cc=vishal.l.verma@intel.com \
--cc=vsethi@nvidia.com \
--cc=yishaih@nvidia.com \
--cc=zhiw@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox