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

From: Srirangan Madhavan

Date: Tue Aug 04 2026 - 15:37:25 EST


CXL bus reset can clear HDM global control and decoder programming.
Restore cached HDM state after a successful cxl_bus reset while the
IOMMU reset block remains active.

Restore PCI config state first so BARs are valid before HDM MMIO access.
If HDM restore 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, matching cxl_reset.

This restores only HDM component decoder state. It does not restore CXL
Device DVSEC range/control registers.

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 | 17 +++++++++++++++++
drivers/pci/pci.c | 6 ++++++
include/cxl/cxl.h | 6 ++++++
3 files changed, 29 insertions(+)

diff --git a/drivers/cxl/core/resource.c b/drivers/cxl/core/resource.c
index ba0a26276477..daa5e7fa2509 100644
--- a/drivers/cxl/core/resource.c
+++ b/drivers/cxl/core/resource.c
@@ -834,6 +834,23 @@ static int cxl_pci_target_reset_prepare(struct pci_dev *pdev,
return 0;
}

+int cxl_restore_hdm_after_pci_reset(struct pci_dev *pdev)
+{
+ u16 command;
+ int rc;
+
+ device_lock_assert(&pdev->dev);
+
+ cxl_restore_pci_state_for_hdm_restore(pdev, &command);
+ rc = cxl_restore_hdm(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 ef25ba5f7fe9..7d1e968a2aa2 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4977,6 +4977,9 @@ static int cxl_reset_bus_function(struct pci_dev *dev, bool probe)
if (!dvsec)
return -ENOTTY;

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

@@ -5004,6 +5007,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_hdm_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 8645d0fbd273..8e6e68751d88 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -162,6 +162,7 @@ struct cxl_hdm_info {
#ifdef CONFIG_CXL_HDM
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);
#else
static inline void pci_cxl_hdm_init(struct pci_dev *pdev)
@@ -172,6 +173,11 @@ static inline void pci_cxl_hdm_release(struct pci_dev *pdev)
{
}

+static inline int cxl_restore_hdm_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