[PATCH v12 12/12] PCI/CXL: Restore CXL state after CXL bus reset

From: Srirangan Madhavan

Date: Thu Sep 10 2026 - 03:16:07 EST


CXL bus reset can clear HDM decoder programming and CXL Device DVSEC
protocol enables. Reuse the common CXL state restore path after a
successful cxl_bus reset while the IOMMU reset block remains active.

Restore PCI config state first so BARs are valid before restoring cached
CXL state. If restoration fails, save a disabled PCI command state so
later PCI restore does not reopen bus mastering over invalid decoder
state.

Reject cxl_bus reset for multifunction devices and PFs with enabled VFs,
matching cxl_reset.

Reported-by: Alex Williamson <alex.williamson@xxxxxxxxxx>
Tested-by: Richard Cheng <icheng@xxxxxxxxxx>
Signed-off-by: Srirangan Madhavan <smadhavan@xxxxxxxxxx>
---
drivers/cxl/core/resource.c | 18 ++++++++++++++++++
drivers/pci/pci.c | 6 ++++++
include/cxl/cxl.h | 6 ++++++
3 files changed, 30 insertions(+)

diff --git a/drivers/cxl/core/resource.c b/drivers/cxl/core/resource.c
index e1d09f9042fa..d3491e20c1ca 100644
--- a/drivers/cxl/core/resource.c
+++ b/drivers/cxl/core/resource.c
@@ -894,6 +894,24 @@ static int cxl_pci_target_reset_prepare(struct pci_dev *pdev,
return 0;
}

+int cxl_restore_state_after_pci_reset(struct pci_dev *pdev)
+{
+ u16 command;
+ int rc;
+
+ device_lock_assert(&pdev->dev);
+ guard(rwsem_write)(&cxl_rwsem.region);
+
+ cxl_restore_pci_state_for_hdm_restore(pdev, &command);
+ rc = cxl_restore_state(pdev);
+ if (rc) {
+ cxl_reset_save_disabled_state(pdev);
+ return rc;
+ }
+
+ return cxl_reset_save_restored_state(pdev, command);
+}
+
static void cxl_hdm_range_context_init(struct cxl_hdm_range_context *ctx)
{
INIT_LIST_HEAD(&ctx->ranges);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 157f06c576e9..a3ba4c28c62b 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -5027,6 +5027,9 @@ static int cxl_reset_bus_function(struct pci_dev *dev, bool probe)
if (!dvsec)
return -ENOTTY;

+ if (dev->multifunction || pci_num_vf(dev))
+ return -ENOTTY;
+
if (probe)
return 0;

@@ -5054,6 +5057,9 @@ static int cxl_reset_bus_function(struct pci_dev *dev, bool probe)
pci_write_config_word(bridge, dvsec + PCI_DVSEC_CXL_PORT_CTL,
reg);

+ if (!rc)
+ rc = cxl_restore_state_after_pci_reset(dev);
+
pci_dev_reset_iommu_done(dev);
return rc;
}
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index 856abbcd5f18..a02792969e0a 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -166,6 +166,7 @@ struct cxl_hdm_info {
#ifdef CONFIG_CXL_RESET
void pci_cxl_hdm_init(struct pci_dev *pdev);
void pci_cxl_hdm_release(struct pci_dev *pdev);
+int cxl_restore_state_after_pci_reset(struct pci_dev *pdev);
int cxl_reset_function(struct pci_dev *pdev, bool probe);
#else
static inline void pci_cxl_hdm_init(struct pci_dev *pdev)
@@ -176,6 +177,11 @@ static inline void pci_cxl_hdm_release(struct pci_dev *pdev)
{
}

+static inline int cxl_restore_state_after_pci_reset(struct pci_dev *pdev)
+{
+ return 0;
+}
+
static inline int cxl_reset_function(struct pci_dev *pdev, bool probe)
{
return -ENOTTY;
--
2.43.0