[RFC PATCH 2/4] PCI/CXL: Populate and insert/remove pdev->coh_resource[]
From: Ankit Agrawal
Date: Mon Oct 05 2026 - 03:04:42 EST
On systems with precommitted HDM decoders, the firmware programs
the decoders before any software runs. This range also stays constant
over the runs.
Snapshot precommitted CXL HDM decoder ranges into a new
pdev->coh_resource[] array, so later code has a known-good source for
a device coherent (CXL) windows without re-scanning decoder
registers.
Signed-off-by: Ankit Agrawal <ankita@xxxxxxxxxx>
Assisted-by: Claude:sonnet-5
---
drivers/cxl/core/resource.c | 52 ++++++++++++++++++++++++++++++++++++-
include/linux/pci.h | 14 ++++++++++
2 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/drivers/cxl/core/resource.c b/drivers/cxl/core/resource.c
index 3422139ae3ab..4d2082c8e321 100644
--- a/drivers/cxl/core/resource.c
+++ b/drivers/cxl/core/resource.c
@@ -404,6 +404,46 @@ static struct cxl_hdm_info *cxl_pci_hdm_read_info(struct pci_dev *pdev,
return ERR_PTR(pcibios_err_to_errno(rc));
}
+/*
+ * Snapshot committed decoders into pdev->coh_resource[] which is called
+ * once per pdev before any driver can bind, so a populated entry is
+ * always firmware-committed and not driver-committed.
+ *
+ * Insert each entry into iomem_resource for /proc/iomem visibility and
+ * conflict detection.
+ */
+static void cxl_populate_coh_resource(struct pci_dev *pdev,
+ struct cxl_hdm_info *info)
+{
+ int count = min(info->decoder_count, PCI_CXL_MAX_COHERENT_RANGES);
+
+ for (int i = 0; i < count; i++) {
+ struct cxl_decoder_config *config = &info->settings[i].config;
+ struct resource *res = &pdev->coh_resource[i];
+ struct resource *conflict;
+
+ if (!(config->flags & CXL_DECODER_F_ENABLE))
+ continue;
+
+ *res = DEFINE_RES_NAMED_DESC(config->hpa_range.start,
+ range_len(&config->hpa_range),
+ "CXL coherent memory",
+ IORESOURCE_MEM, IORES_DESC_NONE);
+
+ conflict = insert_resource_conflict(&iomem_resource, res);
+ if (conflict) {
+ pci_warn(pdev,
+ "CXL coherent range: decoder%d %pR conflicts with %s %pR, leaving unpopulated\n",
+ i, res, conflict->name, conflict);
+ memset(res, 0, sizeof(*res));
+ continue;
+ }
+
+ pci_info(pdev, "CXL coherent range: decoder%d precommitted, populated %pR\n",
+ i, res);
+ }
+}
+
static int __pci_cxl_hdm_cache_init(struct pci_dev *pdev)
{
struct cxl_register_map map = { };
@@ -442,8 +482,10 @@ static int __pci_cxl_hdm_cache_init(struct pci_dev *pdev)
struct cxl_hdm_info *info __free(kfree) = read_info;
guard(rwsem_write)(&cxl_rwsem.dpa);
/* Another initializer may have published while we read MMIO. */
- if (!pdev->hdm)
+ if (!pdev->hdm) {
+ cxl_populate_coh_resource(pdev, info);
pdev->hdm = no_free_ptr(info);
+ }
return 0;
}
@@ -466,6 +508,14 @@ void pci_cxl_hdm_cache_release(struct pci_dev *pdev)
info = pdev->hdm;
/* Unpublish before freeing so subsequent readers cannot use stale state. */
pdev->hdm = NULL;
+
+ for (int i = 0; i < PCI_CXL_MAX_COHERENT_RANGES; i++) {
+ struct resource *res = &pdev->coh_resource[i];
+
+ if (res->parent)
+ remove_resource(res);
+ }
+
kfree(info);
}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index b00f5f38f77d..ce724d067fd2 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -148,6 +148,13 @@ enum {
DEVICE_COUNT_RESOURCE = PCI_NUM_RESOURCES,
};
+/*
+ * Max CXL HDM decoders tracked per endpoint in pci_dev->coh_resource[].
+ * CXL 3.1 spec section 8.2.4.20.1 - CXL HDM Decoder Capability Register,
+ * mention a max of 10 decoders for a CXL device.
+ */
+#define PCI_CXL_MAX_COHERENT_RANGES 10
+
/**
* enum pci_interrupt_pin - PCI INTx interrupt values
* @PCI_INTERRUPT_UNKNOWN: Unknown or unassigned interrupt
@@ -572,6 +579,13 @@ struct pci_dev {
#endif
#ifdef CONFIG_CXL_RESET
struct cxl_hdm_info *hdm; /* CXL HDM decoder state */
+ /*
+ * Precommitted CXL HDM decoder coherent ranges, snapshotted before
+ * any driver binds. One entry per decoder index. Only written by
+ * pci_cxl_hdm_cache_init()/_release(), outside any bound driver's
+ * read window.
+ */
+ struct resource coh_resource[PCI_CXL_MAX_COHERENT_RANGES];
#endif
#ifdef CONFIG_PCI_NPEM
struct npem *npem; /* Native PCIe Enclosure Management */
--
2.43.0