* [PATCH v3 1/10] cxl: move DVSEC defines to cxl pci header
2026-01-16 1:41 [PATCH v3 0/10] CXL reset support for Type 2 devices smadhavan
@ 2026-01-16 1:41 ` smadhavan
2026-01-16 1:41 ` [PATCH v3 2/10] PCI: switch CXL port DVSEC defines smadhavan
` (9 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: smadhavan @ 2026-01-16 1:41 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: smadhavan, vaslot, vsethi, sdonthineni, vidyas, mochs, jsequeira
From: Srirangan Madhavan <smadhavan@nvidia.com>
CXL DVSEC definitions are shared across PCI core and CXL drivers, so
move the register macros into the common CXL PCI header. This keeps
the DVSEC surface in one place and avoids duplication as the reset and
config helpers build on these offsets and bitfields.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
---
drivers/cxl/core/pci.c | 1 +
drivers/cxl/core/regs.c | 1 +
drivers/cxl/cxlpci.h | 53 -----------------------------------
drivers/cxl/pci.c | 1 +
include/cxl/pci.h | 62 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 65 insertions(+), 53 deletions(-)
create mode 100644 include/cxl/pci.h
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 5b023a0178a4..968babcc09a2 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -7,6 +7,7 @@
#include <linux/pci.h>
#include <linux/pci-doe.h>
#include <linux/aer.h>
+#include <cxl/pci.h>
#include <cxlpci.h>
#include <cxlmem.h>
#include <cxl.h>
diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index 5ca7b0eed568..ecdb22ae6952 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -4,6 +4,7 @@
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <cxl/pci.h>
#include <cxlmem.h>
#include <cxlpci.h>
#include <pmu.h>
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 1d526bea8431..cdb7cf3dbcb4 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -7,59 +7,6 @@
#define CXL_MEMORY_PROGIF 0x10
-/*
- * See section 8.1 Configuration Space Registers in the CXL 2.0
- * Specification. Names are taken straight from the specification with "CXL" and
- * "DVSEC" redundancies removed. When obvious, abbreviations may be used.
- */
-#define PCI_DVSEC_HEADER1_LENGTH_MASK GENMASK(31, 20)
-
-/* CXL 2.0 8.1.3: PCIe DVSEC for CXL Device */
-#define CXL_DVSEC_PCIE_DEVICE 0
-#define CXL_DVSEC_CAP_OFFSET 0xA
-#define CXL_DVSEC_MEM_CAPABLE BIT(2)
-#define CXL_DVSEC_HDM_COUNT_MASK GENMASK(5, 4)
-#define CXL_DVSEC_CTRL_OFFSET 0xC
-#define CXL_DVSEC_MEM_ENABLE BIT(2)
-#define CXL_DVSEC_RANGE_SIZE_HIGH(i) (0x18 + (i * 0x10))
-#define CXL_DVSEC_RANGE_SIZE_LOW(i) (0x1C + (i * 0x10))
-#define CXL_DVSEC_MEM_INFO_VALID BIT(0)
-#define CXL_DVSEC_MEM_ACTIVE BIT(1)
-#define CXL_DVSEC_MEM_SIZE_LOW_MASK GENMASK(31, 28)
-#define CXL_DVSEC_RANGE_BASE_HIGH(i) (0x20 + (i * 0x10))
-#define CXL_DVSEC_RANGE_BASE_LOW(i) (0x24 + (i * 0x10))
-#define CXL_DVSEC_MEM_BASE_LOW_MASK GENMASK(31, 28)
-
-#define CXL_DVSEC_RANGE_MAX 2
-
-/* CXL 2.0 8.1.4: Non-CXL Function Map DVSEC */
-#define CXL_DVSEC_FUNCTION_MAP 2
-
-/* CXL 2.0 8.1.5: CXL 2.0 Extensions DVSEC for Ports */
-#define CXL_DVSEC_PORT_EXTENSIONS 3
-
-/* CXL 2.0 8.1.6: GPF DVSEC for CXL Port */
-#define CXL_DVSEC_PORT_GPF 4
-#define CXL_DVSEC_PORT_GPF_PHASE_1_CONTROL_OFFSET 0x0C
-#define CXL_DVSEC_PORT_GPF_PHASE_1_TMO_BASE_MASK GENMASK(3, 0)
-#define CXL_DVSEC_PORT_GPF_PHASE_1_TMO_SCALE_MASK GENMASK(11, 8)
-#define CXL_DVSEC_PORT_GPF_PHASE_2_CONTROL_OFFSET 0xE
-#define CXL_DVSEC_PORT_GPF_PHASE_2_TMO_BASE_MASK GENMASK(3, 0)
-#define CXL_DVSEC_PORT_GPF_PHASE_2_TMO_SCALE_MASK GENMASK(11, 8)
-
-/* CXL 2.0 8.1.7: GPF DVSEC for CXL Device */
-#define CXL_DVSEC_DEVICE_GPF 5
-
-/* CXL 2.0 8.1.8: PCIe DVSEC for Flex Bus Port */
-#define CXL_DVSEC_PCIE_FLEXBUS_PORT 7
-
-/* CXL 2.0 8.1.9: Register Locator DVSEC */
-#define CXL_DVSEC_REG_LOCATOR 8
-#define CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET 0xC
-#define CXL_DVSEC_REG_LOCATOR_BIR_MASK GENMASK(2, 0)
-#define CXL_DVSEC_REG_LOCATOR_BLOCK_ID_MASK GENMASK(15, 8)
-#define CXL_DVSEC_REG_LOCATOR_BLOCK_OFF_LOW_MASK GENMASK(31, 16)
-
/*
* NOTE: Currently all the functions which are enabled for CXL require their
* vectors to be in the first 16. Use this as the default max.
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 0be4e508affe..afcdf6c56065 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -12,6 +12,7 @@
#include <linux/aer.h>
#include <linux/io.h>
#include <cxl/mailbox.h>
+#include <cxl/pci.h>
#include "cxlmem.h"
#include "cxlpci.h"
#include "cxl.h"
diff --git a/include/cxl/pci.h b/include/cxl/pci.h
new file mode 100644
index 000000000000..728ba0cdd289
--- /dev/null
+++ b/include/cxl/pci.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(c) 2020 Intel Corporation. All rights reserved. */
+
+#ifndef __CXL_ACCEL_PCI_H
+#define __CXL_ACCEL_PCI_H
+
+/*
+ * See section 8.1 Configuration Space Registers in the CXL 2.0
+ * Specification. Names are taken straight from the specification with "CXL" and
+ * "DVSEC" redundancies removed. When obvious, abbreviations may be used.
+ */
+#define PCI_DVSEC_HEADER1_LENGTH_MASK GENMASK(31, 20)
+
+/* CXL 2.0 8.1.3: PCIe DVSEC for CXL Device */
+#define CXL_DVSEC_PCIE_DEVICE 0
+#define CXL_DVSEC_CAP_OFFSET 0xA
+#define CXL_DVSEC_MEM_CAPABLE BIT(2)
+#define CXL_DVSEC_HDM_COUNT_MASK GENMASK(5, 4)
+#define CXL_DVSEC_CTRL_OFFSET 0xC
+#define CXL_DVSEC_MEM_ENABLE BIT(2)
+#define CXL_DVSEC_RANGE_SIZE_HIGH(i) (0x18 + ((i) * 0x10))
+#define CXL_DVSEC_RANGE_SIZE_LOW(i) (0x1C + ((i) * 0x10))
+#define CXL_DVSEC_MEM_INFO_VALID BIT(0)
+#define CXL_DVSEC_MEM_ACTIVE BIT(1)
+#define CXL_DVSEC_MEM_SIZE_LOW_MASK GENMASK(31, 28)
+#define CXL_DVSEC_RANGE_BASE_HIGH(i) (0x20 + ((i) * 0x10))
+#define CXL_DVSEC_RANGE_BASE_LOW(i) (0x24 + ((i) * 0x10))
+#define CXL_DVSEC_MEM_BASE_LOW_MASK GENMASK(31, 28)
+
+#define CXL_DVSEC_RANGE_MAX 2
+
+/* CXL 2.0 8.1.4: Non-CXL Function Map DVSEC */
+#define CXL_DVSEC_FUNCTION_MAP 2
+
+/* CXL 2.0 8.1.5: CXL 2.0 Extensions DVSEC for Ports */
+#define CXL_DVSEC_PORT_EXTENSIONS 3
+#define CXL_DVSEC_PORT_CTL 0xC
+#define CXL_DVSEC_UNMASK_SBR BIT(0)
+
+/* CXL 2.0 8.1.6: GPF DVSEC for CXL Port */
+#define CXL_DVSEC_PORT_GPF 4
+#define CXL_DVSEC_PORT_GPF_PHASE_1_CONTROL_OFFSET 0x0C
+#define CXL_DVSEC_PORT_GPF_PHASE_1_TMO_BASE_MASK GENMASK(3, 0)
+#define CXL_DVSEC_PORT_GPF_PHASE_1_TMO_SCALE_MASK GENMASK(11, 8)
+#define CXL_DVSEC_PORT_GPF_PHASE_2_CONTROL_OFFSET 0xE
+#define CXL_DVSEC_PORT_GPF_PHASE_2_TMO_BASE_MASK GENMASK(3, 0)
+#define CXL_DVSEC_PORT_GPF_PHASE_2_TMO_SCALE_MASK GENMASK(11, 8)
+
+/* CXL 2.0 8.1.7: GPF DVSEC for CXL Device */
+#define CXL_DVSEC_DEVICE_GPF 5
+
+/* CXL 2.0 8.1.8: PCIe DVSEC for Flex Bus Port */
+#define CXL_DVSEC_PCIE_FLEXBUS_PORT 7
+
+/* CXL 2.0 8.1.9: Register Locator DVSEC */
+#define CXL_DVSEC_REG_LOCATOR 8
+#define CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET 0xC
+#define CXL_DVSEC_REG_LOCATOR_BIR_MASK GENMASK(2, 0)
+#define CXL_DVSEC_REG_LOCATOR_BLOCK_ID_MASK GENMASK(15, 8)
+#define CXL_DVSEC_REG_LOCATOR_BLOCK_OFF_LOW_MASK GENMASK(31, 16)
+
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 2/10] PCI: switch CXL port DVSEC defines
2026-01-16 1:41 [PATCH v3 0/10] CXL reset support for Type 2 devices smadhavan
2026-01-16 1:41 ` [PATCH v3 1/10] cxl: move DVSEC defines to cxl pci header smadhavan
@ 2026-01-16 1:41 ` smadhavan
2026-01-16 1:41 ` [PATCH v3 3/10] cxl: add type 2 helper and reset DVSEC bits smadhavan
` (8 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: smadhavan @ 2026-01-16 1:41 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: smadhavan, vaslot, vsethi, sdonthineni, vidyas, mochs, jsequeira
From: Srirangan Madhavan <smadhavan@nvidia.com>
The PCI core consumes CXL port DVSEC fields for reset handling, so
switch it to use the shared CXL PCI header instead of the uapi header.
This aligns the core with the header split and keeps internal code from
depending on uapi-only definitions.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
---
drivers/pci/pci.c | 17 +++++++++--------
include/uapi/linux/pci_regs.h | 5 -----
2 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 13dbb405dc31..8bb07e253646 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -30,6 +30,7 @@
#include <asm/dma.h>
#include <linux/aer.h>
#include <linux/bitfield.h>
+#include <cxl/pci.h>
#include "pci.h"
DEFINE_MUTEX(pci_slot_mutex);
@@ -4842,7 +4843,7 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, bool probe)
static u16 cxl_port_dvsec(struct pci_dev *dev)
{
return pci_find_dvsec_capability(dev, PCI_VENDOR_ID_CXL,
- PCI_DVSEC_CXL_PORT);
+ CXL_DVSEC_PORT_EXTENSIONS);
}
static bool cxl_sbr_masked(struct pci_dev *dev)
@@ -4854,7 +4855,7 @@ static bool cxl_sbr_masked(struct pci_dev *dev)
if (!dvsec)
return false;
- rc = pci_read_config_word(dev, dvsec + PCI_DVSEC_CXL_PORT_CTL, ®);
+ rc = pci_read_config_word(dev, dvsec + CXL_DVSEC_PORT_CTL, ®);
if (rc || PCI_POSSIBLE_ERROR(reg))
return false;
@@ -4863,7 +4864,7 @@ static bool cxl_sbr_masked(struct pci_dev *dev)
* bit in Bridge Control has no effect. When 1, the Port generates
* hot reset when the SBR bit is set to 1.
*/
- if (reg & PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR)
+ if (reg & CXL_DVSEC_UNMASK_SBR)
return false;
return true;
@@ -4908,22 +4909,22 @@ static int cxl_reset_bus_function(struct pci_dev *dev, bool probe)
if (probe)
return 0;
- rc = pci_read_config_word(bridge, dvsec + PCI_DVSEC_CXL_PORT_CTL, ®);
+ rc = pci_read_config_word(bridge, dvsec + CXL_DVSEC_PORT_CTL, ®);
if (rc)
return -ENOTTY;
- if (reg & PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR) {
+ if (reg & CXL_DVSEC_UNMASK_SBR) {
val = reg;
} else {
- val = reg | PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR;
- pci_write_config_word(bridge, dvsec + PCI_DVSEC_CXL_PORT_CTL,
+ val = reg | CXL_DVSEC_UNMASK_SBR;
+ pci_write_config_word(bridge, dvsec + CXL_DVSEC_PORT_CTL,
val);
}
rc = pci_reset_bus_function(dev, probe);
if (reg != val)
- pci_write_config_word(bridge, dvsec + PCI_DVSEC_CXL_PORT_CTL,
+ pci_write_config_word(bridge, dvsec + CXL_DVSEC_PORT_CTL,
reg);
return rc;
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index 3add74ae2594..4f9e6dddc282 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -1253,11 +1253,6 @@
#define PCI_DEV3_STA 0x0c /* Device 3 Status Register */
#define PCI_DEV3_STA_SEGMENT 0x8 /* Segment Captured (end-to-end flit-mode detected) */
-/* Compute Express Link (CXL r3.1, sec 8.1.5) */
-#define PCI_DVSEC_CXL_PORT 3
-#define PCI_DVSEC_CXL_PORT_CTL 0x0c
-#define PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR 0x00000001
-
/* Integrity and Data Encryption Extended Capability */
#define PCI_IDE_CAP 0x04
#define PCI_IDE_CAP_LINK 0x1 /* Link IDE Stream Supported */
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 3/10] cxl: add type 2 helper and reset DVSEC bits
2026-01-16 1:41 [PATCH v3 0/10] CXL reset support for Type 2 devices smadhavan
2026-01-16 1:41 ` [PATCH v3 1/10] cxl: move DVSEC defines to cxl pci header smadhavan
2026-01-16 1:41 ` [PATCH v3 2/10] PCI: switch CXL port DVSEC defines smadhavan
@ 2026-01-16 1:41 ` smadhavan
2026-01-16 1:41 ` [PATCH v3 4/10] PCI: add CXL reset method smadhavan
` (7 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: smadhavan @ 2026-01-16 1:41 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: smadhavan, vaslot, vsethi, sdonthineni, vidyas, mochs, jsequeira
From: Srirangan Madhavan <smadhavan@nvidia.com>
Introduce a helper to identify CXL Type 2 devices and define the DVSEC
reset/cache control bits used by the reset flow.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
---
drivers/cxl/pci.c | 10 ++++++++++
include/cxl/pci.h | 14 ++++++++++++++
2 files changed, 24 insertions(+)
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index afcdf6c56065..6fedeaea6185 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -1082,6 +1082,16 @@ static pci_ers_result_t cxl_slot_reset(struct pci_dev *pdev)
return PCI_ERS_RESULT_RECOVERED;
}
+bool cxl_is_type2_device(struct pci_dev *pdev)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+
+ if (!cxlds)
+ return false;
+
+ return cxlds->type == CXL_DEVTYPE_DEVMEM;
+}
+
static void cxl_error_resume(struct pci_dev *pdev)
{
struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
diff --git a/include/cxl/pci.h b/include/cxl/pci.h
index 728ba0cdd289..71d8de5de948 100644
--- a/include/cxl/pci.h
+++ b/include/cxl/pci.h
@@ -14,10 +14,24 @@
/* CXL 2.0 8.1.3: PCIe DVSEC for CXL Device */
#define CXL_DVSEC_PCIE_DEVICE 0
#define CXL_DVSEC_CAP_OFFSET 0xA
+#define CXL_DVSEC_CACHE_CAPABLE BIT(0)
#define CXL_DVSEC_MEM_CAPABLE BIT(2)
#define CXL_DVSEC_HDM_COUNT_MASK GENMASK(5, 4)
+#define CXL_DVSEC_CACHE_WBI_CAPABLE BIT(6)
+#define CXL_DVSEC_CXL_RST_CAPABLE BIT(7)
+#define CXL_DVSEC_CXL_RST_TIMEOUT_MASK GENMASK(10, 8)
+#define CXL_DVSEC_CXL_RST_MEM_CLR_CAPABLE BIT(11)
#define CXL_DVSEC_CTRL_OFFSET 0xC
#define CXL_DVSEC_MEM_ENABLE BIT(2)
+#define CXL_DVSEC_CTRL2_OFFSET 0x10
+#define CXL_DVSEC_DISABLE_CACHING BIT(0)
+#define CXL_DVSEC_INIT_CACHE_WBI BIT(1)
+#define CXL_DVSEC_INIT_CXL_RESET BIT(2)
+#define CXL_DVSEC_CXL_RST_MEM_CLR_ENABLE BIT(3)
+#define CXL_DVSEC_STATUS2_OFFSET 0x12
+#define CXL_DVSEC_CACHE_INVALID BIT(0)
+#define CXL_DVSEC_CXL_RST_COMPLETE BIT(1)
+#define CXL_DVSEC_CXL_RESET_ERR BIT(2)
#define CXL_DVSEC_RANGE_SIZE_HIGH(i) (0x18 + ((i) * 0x10))
#define CXL_DVSEC_RANGE_SIZE_LOW(i) (0x1C + ((i) * 0x10))
#define CXL_DVSEC_MEM_INFO_VALID BIT(0)
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 4/10] PCI: add CXL reset method
2026-01-16 1:41 [PATCH v3 0/10] CXL reset support for Type 2 devices smadhavan
` (2 preceding siblings ...)
2026-01-16 1:41 ` [PATCH v3 3/10] cxl: add type 2 helper and reset DVSEC bits smadhavan
@ 2026-01-16 1:41 ` smadhavan
2026-01-17 13:56 ` kernel test robot
2026-01-17 14:28 ` kernel test robot
2026-01-16 1:41 ` [PATCH v3 5/10] cxl: add reset prepare and region teardown smadhavan
` (6 subsequent siblings)
10 siblings, 2 replies; 16+ messages in thread
From: smadhavan @ 2026-01-16 1:41 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: smadhavan, vaslot, vsethi, sdonthineni, vidyas, mochs, jsequeira,
Srirangan Madhavan
From: Srirangan Madhavan <smadhavan@nvidia.com>
Add a PCI reset method "cxl_reset" that drives the CXL reset sequence using
DVSEC controls and timeout encoding. The method is restricted to
Type 2 devices, limiting the scope of the changes.
Signed-off-by: Srirangan Madhavan <smsadhavan@nvidia.com>
---
drivers/pci/pci.c | 100 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 3 +-
2 files changed, 102 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8bb07e253646..b3eb82b21c35 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4892,6 +4892,105 @@ static int pci_reset_bus_function(struct pci_dev *dev, bool probe)
return pci_parent_bus_reset(dev, probe);
}
+static int cxl_reset_init(struct pci_dev *dev, u16 dvsec)
+{
+ /*
+ * Timeout values ref CXL Spec v3.2 Ch 8 Control and Status Registers,
+ * under section 8.1.3.1 DVSEC CXL Capability.
+ */
+ u32 reset_timeouts_ms[] = { 10, 100, 1000, 10000, 100000 };
+ u16 reg;
+ u32 timeout_ms;
+ int rc, ind;
+
+ /* Check if CXL Reset MEM CLR is supported. */
+ rc = pci_read_config_word(dev, dvsec + CXL_DVSEC_CAP_OFFSET, ®);
+ if (rc)
+ return rc;
+
+ if (reg & CXL_DVSEC_CXL_RST_MEM_CLR_CAPABLE) {
+ rc = pci_read_config_word(dev, dvsec + CXL_DVSEC_CTRL2_OFFSET,
+ ®);
+ if (rc)
+ return rc;
+
+ reg |= CXL_DVSEC_CXL_RST_MEM_CLR_ENABLE;
+ pci_write_config_word(dev, dvsec + CXL_DVSEC_CTRL2_OFFSET, reg);
+ }
+
+ /* Read timeout value. */
+ rc = pci_read_config_word(dev, dvsec + CXL_DVSEC_CAP_OFFSET, ®);
+ if (rc)
+ return rc;
+ ind = FIELD_GET(CXL_DVSEC_CXL_RST_TIMEOUT_MASK, reg);
+ timeout_ms = reset_timeouts_ms[ind];
+
+ /* Write reset config. */
+ rc = pci_read_config_word(dev, dvsec + CXL_DVSEC_CTRL2_OFFSET, ®);
+ if (rc)
+ return rc;
+
+ reg |= CXL_DVSEC_INIT_CXL_RESET;
+ pci_write_config_word(dev, dvsec + CXL_DVSEC_CTRL2_OFFSET, reg);
+
+ /* Wait till timeout and then check reset status is complete. */
+ msleep(timeout_ms);
+ rc = pci_read_config_word(dev, dvsec + CXL_DVSEC_STATUS2_OFFSET, ®);
+ if (rc)
+ return rc;
+ if (reg & CXL_DVSEC_CXL_RESET_ERR ||
+ ~reg & CXL_DVSEC_CXL_RST_COMPLETE)
+ return -ETIMEDOUT;
+
+ rc = pci_read_config_word(dev, dvsec + CXL_DVSEC_CTRL2_OFFSET, ®);
+ if (rc)
+ return rc;
+ reg &= (~CXL_DVSEC_DISABLE_CACHING);
+ pci_write_config_word(dev, dvsec + CXL_DVSEC_CTRL2_OFFSET, reg);
+
+ return 0;
+}
+
+/**
+ * cxl_reset - initiate a cxl reset
+ * @dev: device to reset
+ * @probe: if true, return 0 if device can be reset this way
+ *
+ * Initiate a cxl reset on @dev.
+ */
+static int cxl_reset(struct pci_dev *dev, bool probe)
+{
+ u16 dvsec, reg;
+ int rc;
+
+ dvsec = pci_find_dvsec_capability(dev, PCI_VENDOR_ID_CXL,
+ CXL_DVSEC_PCIE_DEVICE);
+ if (!dvsec)
+ return -ENOTTY;
+
+ /* Check if CXL Reset is supported. */
+ rc = pci_read_config_word(dev, dvsec + CXL_DVSEC_CAP_OFFSET, ®);
+ if (rc)
+ return -ENOTTY;
+
+ if (reg & CXL_DVSEC_CXL_RST_CAPABLE == 0)
+ return -ENOTTY;
+
+ /*
+ * Expose CXL reset for Type 2 devices.
+ */
+ if (!cxl_is_type2_device(dev))
+ return -ENOTTY;
+
+ if (probe)
+ return 0;
+
+ if (!pci_wait_for_pending_transaction(dev))
+ pci_err(dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
+
+ return cxl_reset_init(dev, dvsec);
+}
+
static int cxl_reset_bus_function(struct pci_dev *dev, bool probe)
{
struct pci_dev *bridge;
@@ -5016,6 +5115,7 @@ const struct pci_reset_fn_method pci_reset_fn_methods[] = {
{ pci_dev_acpi_reset, .name = "acpi" },
{ pcie_reset_flr, .name = "flr" },
{ pci_af_flr, .name = "af_flr" },
+ { cxl_reset, .name = "cxl_reset" },
{ pci_pm_reset, .name = "pm" },
{ pci_reset_bus_function, .name = "bus" },
{ cxl_reset_bus_function, .name = "cxl_bus" },
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 864775651c6f..056eff0b1e86 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -51,7 +51,7 @@
PCI_STATUS_PARITY)
/* Number of reset methods used in pci_reset_fn_methods array in pci.c */
-#define PCI_NUM_RESET_METHODS 8
+#define PCI_NUM_RESET_METHODS 9
#define PCI_RESET_PROBE true
#define PCI_RESET_DO_RESET false
@@ -1464,6 +1464,7 @@ int __must_check pci_resize_resource(struct pci_dev *dev, int i, int size,
int pci_select_bars(struct pci_dev *dev, unsigned long flags);
bool pci_device_is_present(struct pci_dev *pdev);
+bool cxl_is_type2_device(struct pci_dev *dev);
void pci_ignore_hotplug(struct pci_dev *dev);
struct pci_dev *pci_real_dma_dev(struct pci_dev *dev);
int pci_status_get_and_clear_errors(struct pci_dev *pdev);
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v3 4/10] PCI: add CXL reset method
2026-01-16 1:41 ` [PATCH v3 4/10] PCI: add CXL reset method smadhavan
@ 2026-01-17 13:56 ` kernel test robot
2026-01-17 14:28 ` kernel test robot
1 sibling, 0 replies; 16+ messages in thread
From: kernel test robot @ 2026-01-17 13:56 UTC (permalink / raw)
To: smadhavan, dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: oe-kbuild-all, smadhavan, vaslot, vsethi, sdonthineni, vidyas,
mochs, jsequeira, Srirangan Madhavan
Hi,
kernel test robot noticed the following build errors:
[auto build test ERROR on pci/next]
[also build test ERROR on pci/for-linus linus/master v6.19-rc5]
[cannot apply to next-20260116]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/smadhavan-nvidia-com/cxl-move-DVSEC-defines-to-cxl-pci-header/20260116-094457
base: https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link: https://lore.kernel.org/r/20260116014146.2149236-5-smadhavan%40nvidia.com
patch subject: [PATCH v3 4/10] PCI: add CXL reset method
config: alpha-allnoconfig (https://download.01.org/0day-ci/archive/20260117/202601172149.u8U2DH7L-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260117/202601172149.u8U2DH7L-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601172149.u8U2DH7L-lkp@intel.com/
All error/warnings (new ones prefixed by >>):
drivers/pci/pci.c: In function 'cxl_reset':
>> drivers/pci/pci.c:4979:17: warning: suggest parentheses around comparison in operand of '&' [-Wparentheses]
4979 | if (reg & CXL_DVSEC_CXL_RST_CAPABLE == 0)
| ^
--
alpha-linux-ld: drivers/pci/pci.o: in function `cxl_reset':
>> (.text+0x6cec): undefined reference to `cxl_is_type2_device'
>> alpha-linux-ld: (.text+0x6cf4): undefined reference to `cxl_is_type2_device'
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v3 4/10] PCI: add CXL reset method
2026-01-16 1:41 ` [PATCH v3 4/10] PCI: add CXL reset method smadhavan
2026-01-17 13:56 ` kernel test robot
@ 2026-01-17 14:28 ` kernel test robot
1 sibling, 0 replies; 16+ messages in thread
From: kernel test robot @ 2026-01-17 14:28 UTC (permalink / raw)
To: smadhavan, dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: llvm, oe-kbuild-all, smadhavan, vaslot, vsethi, sdonthineni,
vidyas, mochs, jsequeira, Srirangan Madhavan
Hi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on pci/next]
[also build test WARNING on pci/for-linus linus/master v6.19-rc5]
[cannot apply to next-20260116]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/smadhavan-nvidia-com/cxl-move-DVSEC-defines-to-cxl-pci-header/20260116-094457
base: https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link: https://lore.kernel.org/r/20260116014146.2149236-5-smadhavan%40nvidia.com
patch subject: [PATCH v3 4/10] PCI: add CXL reset method
config: loongarch-allnoconfig (https://download.01.org/0day-ci/archive/20260117/202601172246.rz4Orygn-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 9b8addffa70cee5b2acc5454712d9cf78ce45710)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260117/202601172246.rz4Orygn-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601172246.rz4Orygn-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/pci/pci.c:4979:10: warning: & has lower precedence than ==; == will be evaluated first [-Wparentheses]
4979 | if (reg & CXL_DVSEC_CXL_RST_CAPABLE == 0)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/pci/pci.c:4979:10: note: place parentheses around the '==' expression to silence this warning
4979 | if (reg & CXL_DVSEC_CXL_RST_CAPABLE == 0)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/pci/pci.c:4979:10: note: place parentheses around the & expression to evaluate it first
4979 | if (reg & CXL_DVSEC_CXL_RST_CAPABLE == 0)
| ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
vim +4979 drivers/pci/pci.c
4956
4957 /**
4958 * cxl_reset - initiate a cxl reset
4959 * @dev: device to reset
4960 * @probe: if true, return 0 if device can be reset this way
4961 *
4962 * Initiate a cxl reset on @dev.
4963 */
4964 static int cxl_reset(struct pci_dev *dev, bool probe)
4965 {
4966 u16 dvsec, reg;
4967 int rc;
4968
4969 dvsec = pci_find_dvsec_capability(dev, PCI_VENDOR_ID_CXL,
4970 CXL_DVSEC_PCIE_DEVICE);
4971 if (!dvsec)
4972 return -ENOTTY;
4973
4974 /* Check if CXL Reset is supported. */
4975 rc = pci_read_config_word(dev, dvsec + CXL_DVSEC_CAP_OFFSET, ®);
4976 if (rc)
4977 return -ENOTTY;
4978
> 4979 if (reg & CXL_DVSEC_CXL_RST_CAPABLE == 0)
4980 return -ENOTTY;
4981
4982 /*
4983 * Expose CXL reset for Type 2 devices.
4984 */
4985 if (!cxl_is_type2_device(dev))
4986 return -ENOTTY;
4987
4988 if (probe)
4989 return 0;
4990
4991 if (!pci_wait_for_pending_transaction(dev))
4992 pci_err(dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
4993
4994 return cxl_reset_init(dev, dvsec);
4995 }
4996
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 5/10] cxl: add reset prepare and region teardown
2026-01-16 1:41 [PATCH v3 0/10] CXL reset support for Type 2 devices smadhavan
` (3 preceding siblings ...)
2026-01-16 1:41 ` [PATCH v3 4/10] PCI: add CXL reset method smadhavan
@ 2026-01-16 1:41 ` smadhavan
2026-01-16 1:41 ` [PATCH v3 6/10] PCI: wire CXL reset prepare/cleanup smadhavan
` (5 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: smadhavan @ 2026-01-16 1:41 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: smadhavan, vaslot, vsethi, sdonthineni, vidyas, mochs, jsequeira
From: Srirangan Madhavan <smadhavan@nvidia.com>
Prepare a Type 2 device for cxl_reset by validating memory is offline,
flushing device caches for region participants, and tearing down decoders
under cxl_region_rwsem. The lock stays held across reset to prevent new
region creation while reset is in progress.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
---
drivers/cxl/pci.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 214 insertions(+)
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 6fedeaea6185..8da69c2125af 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -1092,6 +1092,220 @@ bool cxl_is_type2_device(struct pci_dev *pdev)
return cxlds->type == CXL_DEVTYPE_DEVMEM;
}
+static int cxl_check_region_driver_bound(struct device *dev, void *data)
+{
+ struct cxl_decoder *cxld = to_cxl_decoder(dev);
+
+ if (!is_endpoint_decoder(dev))
+ return 0;
+
+ guard(rwsem_read)(&cxl_region_rwsem);
+ if (cxld->region && cxld->region->driver)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int cxl_decoder_kill_region_iter(struct device *dev, void *data)
+{
+ struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+ int rc;
+
+ if (!is_endpoint_decoder(dev))
+ return 0;
+
+ if (!cxled->cxld.region)
+ return 0;
+
+ cxl_decoder_kill_region_locked(cxled);
+
+ rc = device_for_each_child(&cxled->cxld.dev, NULL,
+ cxl_check_region_driver_bound);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static int cxl_device_cache_wb_invalidate(struct pci_dev *pdev)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ u16 reg, val, cap;
+ int dvsec, rc;
+
+ if (!cxlds)
+ return -ENODEV;
+
+ dvsec = cxlds->cxl_dvsec;
+ if (!dvsec)
+ return -ENODEV;
+
+ rc = pci_read_config_word(pdev, dvsec + CXL_DVSEC_CAP_OFFSET, &cap);
+ if (rc)
+ return rc;
+
+ if (!(cap & CXL_DVSEC_CACHE_WBI_CAPABLE))
+ return 1;
+
+ rc = pci_read_config_word(pdev, dvsec + CXL_DVSEC_CTRL2_OFFSET, &val);
+ if (rc)
+ return rc;
+
+ val |= CXL_DVSEC_INIT_CACHE_WBI;
+ rc = pci_write_config_word(pdev, dvsec + CXL_DVSEC_CTRL2_OFFSET, val);
+ if (rc)
+ return rc;
+
+ do {
+ rc = pci_read_config_word(pdev, dvsec + CXL_DVSEC_STATUS2_OFFSET, ®);
+ if (rc)
+ return rc;
+ } while (!(reg & CXL_DVSEC_CACHE_INVALID));
+
+ return 0;
+}
+
+static int cxl_region_flush_device_caches(struct device *dev, void *data)
+{
+ struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+ struct cxl_region *cxlr = cxled->cxld.region;
+ struct cxl_region_params *p = &cxlr->params;
+ struct pci_dev *target_pdev = data;
+ int i, rc;
+
+ if (!is_endpoint_decoder(dev))
+ return 0;
+
+ if (!cxlr || !cxlr->params.res)
+ return 0;
+
+ for (i = 0; i < p->nr_targets; i++) {
+ struct cxl_endpoint_decoder *target_cxled = p->targets[i];
+ struct cxl_memdev *target_cxlmd = cxled_to_memdev(target_cxled);
+ struct cxl_dev_state *target_cxlds = target_cxlmd->cxlds;
+
+ if (!target_cxlds || !target_cxlds->pdev)
+ continue;
+
+ if (target_cxlds->pdev != target_pdev)
+ continue;
+
+ rc = cxl_device_cache_wb_invalidate(target_pdev);
+ if (rc && rc != 1)
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * cxl_reset_prepare_memdev - Prepare CXL device for reset
+ * @pdev: PCI device
+ *
+ * Validates it's safe to reset and tears down regions atomically under lock.
+ * Acquires cxl_region_rwsem and keeps it held throughout reset.
+ *
+ * Return: 0 on success (lock held), -EBUSY if memory online, negative on error
+ */
+static int cxl_reset_prepare_memdev(struct pci_dev *pdev)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ struct cxl_memdev *cxlmd;
+ struct cxl_port *endpoint;
+ int rc;
+
+ if (!cxlds)
+ return -ENODEV;
+
+ cxlmd = cxlds->cxlmd;
+ if (!cxlmd)
+ return -ENODEV;
+
+ endpoint = cxlmd->endpoint;
+ if (!endpoint)
+ return 0;
+
+ if (cxl_num_decoders_committed(endpoint) == 0)
+ return 0;
+
+ down_write(&cxl_region_rwsem);
+
+ /* Check and error out if memory is online */
+ rc = device_for_each_child(&endpoint->dev, NULL,
+ cxl_check_region_driver_bound);
+ if (rc) {
+ up_write(&cxl_region_rwsem);
+ dev_err(&pdev->dev,
+ "Reset blocked: device has active regions with drivers bound\n");
+ return -EBUSY;
+ }
+
+ /* Flush device caches and tear down regions */
+ device_for_each_child(&endpoint->dev, pdev,
+ cxl_region_flush_device_caches);
+
+ rc = device_for_each_child(&endpoint->dev, NULL,
+ cxl_decoder_kill_region_iter);
+ if (rc) {
+ up_write(&cxl_region_rwsem);
+ dev_err(&pdev->dev, "Failed to tear down regions: %d\n", rc);
+ return rc;
+ }
+
+ /* Keep cxl_region_rwsem held, released by cleanup function */
+ return 0;
+}
+
+/**
+ * cxl_reset_cleanup_memdev - Release locks after CXL reset
+ * @pdev: PCI device
+ */
+static void cxl_reset_cleanup_memdev(struct pci_dev *pdev)
+{
+ if (lockdep_is_held_type(&cxl_region_rwsem, -1))
+ up_write(&cxl_region_rwsem);
+}
+
+/**
+ * cxl_reset_prepare_device - Prepare CXL device for reset
+ * @pdev: PCI device being reset
+ *
+ * CXL-reset-specific preparation. Validates memory is offline, flushes
+ * device caches, and tears down regions.
+ *
+ * Returns: 0 on success, -EBUSY if memory online, negative on error
+ */
+int cxl_reset_prepare_device(struct pci_dev *pdev)
+{
+ int rc;
+
+ rc = cxl_reset_prepare_memdev(pdev);
+ if (rc) {
+ if (rc == -EBUSY)
+ dev_err(&pdev->dev,
+ "Cannot reset: device has online memory or active regions\n");
+ else
+ dev_err(&pdev->dev,
+ "Failed to prepare device for reset: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_reset_prepare_device, "CXL");
+
+/**
+ * cxl_reset_cleanup_device - Cleanup after CXL reset
+ * @pdev: PCI device that was reset
+ *
+ * Releases region locks held during reset.
+ */
+void cxl_reset_cleanup_device(struct pci_dev *pdev)
+{
+ cxl_reset_cleanup_memdev(pdev);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_reset_cleanup_device, "CXL");
+
static void cxl_error_resume(struct pci_dev *pdev)
{
struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 6/10] PCI: wire CXL reset prepare/cleanup
2026-01-16 1:41 [PATCH v3 0/10] CXL reset support for Type 2 devices smadhavan
` (4 preceding siblings ...)
2026-01-16 1:41 ` [PATCH v3 5/10] cxl: add reset prepare and region teardown smadhavan
@ 2026-01-16 1:41 ` smadhavan
2026-01-16 1:41 ` [PATCH v3 7/10] cxl: add host cache flush and multi-function reset smadhavan
` (4 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: smadhavan @ 2026-01-16 1:41 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: smadhavan, vaslot, vsethi, sdonthineni, vidyas, mochs, jsequeira
From: Srirangan Madhavan <smadhavan@nvidia.com>
Wire CXL reset preparation and cleanup into the PCI CXL reset path.
The flow now validates/offlines regions, performs teardown and cache
flushes, then releases the lock on completion or error. This keeps the
common reset_prepare flow intact while adding cxl_reset-specific quiesce logic.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
---
drivers/pci/pci.c | 19 ++++++++++++++++++-
include/linux/pci.h | 2 ++
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b3eb82b21c35..83fd7e75a12e 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4985,10 +4985,27 @@ static int cxl_reset(struct pci_dev *dev, bool probe)
if (probe)
return 0;
+ /*
+ * CXL-reset-specific preparation: validate memory offline,
+ * tear down regions, flush device caches.
+ */
+ rc = cxl_reset_prepare_device(dev);
+ if (rc)
+ return rc;
+
if (!pci_wait_for_pending_transaction(dev))
pci_err(dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
- return cxl_reset_init(dev, dvsec);
+ rc = cxl_reset_init(dev, dvsec);
+ if (rc)
+ goto out_cleanup;
+
+ cxl_reset_cleanup_device(dev);
+ return 0;
+
+out_cleanup:
+ cxl_reset_cleanup_device(dev);
+ return rc;
}
static int cxl_reset_bus_function(struct pci_dev *dev, bool probe)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 056eff0b1e86..d29f0bfc84b5 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1465,6 +1465,8 @@ int __must_check pci_resize_resource(struct pci_dev *dev, int i, int size,
int pci_select_bars(struct pci_dev *dev, unsigned long flags);
bool pci_device_is_present(struct pci_dev *pdev);
bool cxl_is_type2_device(struct pci_dev *dev);
+int cxl_reset_prepare_device(struct pci_dev *pdev);
+void cxl_reset_cleanup_device(struct pci_dev *pdev);
void pci_ignore_hotplug(struct pci_dev *dev);
struct pci_dev *pci_real_dma_dev(struct pci_dev *dev);
int pci_status_get_and_clear_errors(struct pci_dev *pdev);
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 7/10] cxl: add host cache flush and multi-function reset
2026-01-16 1:41 [PATCH v3 0/10] CXL reset support for Type 2 devices smadhavan
` (5 preceding siblings ...)
2026-01-16 1:41 ` [PATCH v3 6/10] PCI: wire CXL reset prepare/cleanup smadhavan
@ 2026-01-16 1:41 ` smadhavan
2026-01-16 1:41 ` [PATCH v3 8/10] cxl: add DVSEC config save/restore smadhavan
` (3 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: smadhavan @ 2026-01-16 1:41 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: smadhavan, vaslot, vsethi, sdonthineni, vidyas, mochs, jsequeira
From: Srirangan Madhavan <smadhavan@nvidia.com>
Flush host CPU caches for mapped HDM ranges after teardown and prepare
sibling Type 2 functions on multi-function devices. The host cache
maintenance uses wbinvd_on_all_cpus() on x86 and VA-based PoC clean+
invalidate on arm64 via memremap() and on_each_cpu(), matching the
required ordering before reset.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
---
drivers/cxl/pci.c | 150 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 148 insertions(+), 2 deletions(-)
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 8da69c2125af..5d2bb4431de3 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -11,6 +11,10 @@
#include <linux/pci.h>
#include <linux/aer.h>
#include <linux/io.h>
+#include <linux/align.h>
+#include <linux/cache.h>
+#include <linux/cacheflush.h>
+#include <linux/smp.h>
#include <cxl/mailbox.h>
#include <cxl/pci.h>
#include "cxlmem.h"
@@ -1092,6 +1096,71 @@ bool cxl_is_type2_device(struct pci_dev *pdev)
return cxlds->type == CXL_DEVTYPE_DEVMEM;
}
+#ifdef CONFIG_ARM64
+struct cxl_cache_flush_ctx {
+ void *va;
+ size_t len;
+};
+
+static void cxl_flush_by_va_local(void *info)
+{
+ struct cxl_cache_flush_ctx *ctx = info;
+
+ dcache_clean_inval_poc((unsigned long)ctx->va,
+ (unsigned long)ctx->va + ctx->len);
+ asm volatile("dsb ish" ::: "memory");
+}
+#endif
+
+static int cxl_region_flush_host_cpu_caches(struct device *dev, void *data)
+{
+ struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+ struct cxl_region *cxlr = cxled->cxld.region;
+ struct resource *res;
+
+ if (!is_endpoint_decoder(dev))
+ return 0;
+
+ if (!cxlr || !cxlr->params.res)
+ return 0;
+
+ res = cxlr->params.res;
+
+#ifdef CONFIG_X86
+ static bool flushed;
+
+ if (!flushed) {
+ wbinvd_on_all_cpus();
+ flushed = true;
+ }
+#elif defined(CONFIG_ARM64)
+ void *va;
+ size_t len, line_size = L1_CACHE_BYTES;
+ phys_addr_t start, end, aligned_start, aligned_end;
+ struct cxl_cache_flush_ctx flush_ctx;
+
+ start = res->start;
+ end = res->end;
+
+ aligned_start = ALIGN_DOWN(start, line_size);
+ aligned_end = ALIGN(end + 1, line_size);
+ len = aligned_end - aligned_start;
+
+ va = memremap(aligned_start, len, MEMREMAP_WB);
+ if (!va) {
+ pr_warn("Failed to map region for cache flush\n");
+ return 0;
+ }
+
+ flush_ctx.va = va;
+ flush_ctx.len = len;
+ on_each_cpu(cxl_flush_by_va_local, &flush_ctx, 1);
+
+ memunmap(va);
+#endif
+ return 0;
+}
+
static int cxl_check_region_driver_bound(struct device *dev, void *data)
{
struct cxl_decoder *cxld = to_cxl_decoder(dev);
@@ -1252,6 +1321,9 @@ static int cxl_reset_prepare_memdev(struct pci_dev *pdev)
return rc;
}
+ device_for_each_child(&endpoint->dev, NULL,
+ cxl_region_flush_host_cpu_caches);
+
/* Keep cxl_region_rwsem held, released by cleanup function */
return 0;
}
@@ -1266,12 +1338,79 @@ static void cxl_reset_cleanup_memdev(struct pci_dev *pdev)
up_write(&cxl_region_rwsem);
}
+static int cxl_reset_prepare_all_functions(struct pci_dev *pdev)
+{
+ struct pci_dev *func_dev;
+ unsigned int devfn;
+ int func, rc;
+ struct pci_dev *prepared_funcs[8] = { NULL };
+ int prepared_count = 0;
+
+ for (func = 0; func < 8; func++) {
+ devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), func);
+
+ if (devfn == pdev->devfn)
+ continue;
+
+ func_dev = pci_get_slot(pdev->bus, devfn);
+ if (!func_dev)
+ continue;
+
+ if (!cxl_is_type2_device(func_dev)) {
+ pci_dev_put(func_dev);
+ continue;
+ }
+
+ rc = cxl_reset_prepare_memdev(func_dev);
+ if (rc) {
+ pci_dev_put(func_dev);
+ goto cleanup_funcs;
+ }
+
+ prepared_funcs[prepared_count++] = func_dev;
+ }
+
+ return 0;
+
+cleanup_funcs:
+ for (func = 0; func < prepared_count; func++) {
+ if (prepared_funcs[func]) {
+ cxl_reset_cleanup_memdev(prepared_funcs[func]);
+ pci_dev_put(prepared_funcs[func]);
+ }
+ }
+ return rc;
+}
+
+static void cxl_reset_cleanup_all_functions(struct pci_dev *pdev)
+{
+ struct pci_dev *func_dev;
+ unsigned int devfn;
+ int func;
+
+ for (func = 0; func < 8; func++) {
+ devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), func);
+
+ if (devfn == pdev->devfn)
+ continue;
+
+ func_dev = pci_get_slot(pdev->bus, devfn);
+ if (!func_dev)
+ continue;
+
+ if (cxl_is_type2_device(func_dev))
+ cxl_reset_cleanup_memdev(func_dev);
+
+ pci_dev_put(func_dev);
+ }
+}
+
/**
* cxl_reset_prepare_device - Prepare CXL device for reset
* @pdev: PCI device being reset
*
* CXL-reset-specific preparation. Validates memory is offline, flushes
- * device caches, and tears down regions.
+ * device caches, and tears down regions for device and siblings.
*
* Returns: 0 on success, -EBUSY if memory online, negative on error
*/
@@ -1290,6 +1429,12 @@ int cxl_reset_prepare_device(struct pci_dev *pdev)
return rc;
}
+ rc = cxl_reset_prepare_all_functions(pdev);
+ if (rc) {
+ cxl_reset_cleanup_memdev(pdev);
+ return rc;
+ }
+
return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_reset_prepare_device, "CXL");
@@ -1298,10 +1443,11 @@ EXPORT_SYMBOL_NS_GPL(cxl_reset_prepare_device, "CXL");
* cxl_reset_cleanup_device - Cleanup after CXL reset
* @pdev: PCI device that was reset
*
- * Releases region locks held during reset.
+ * Releases region locks for device and all sibling functions.
*/
void cxl_reset_cleanup_device(struct pci_dev *pdev)
{
+ cxl_reset_cleanup_all_functions(pdev);
cxl_reset_cleanup_memdev(pdev);
}
EXPORT_SYMBOL_NS_GPL(cxl_reset_cleanup_device, "CXL");
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 8/10] cxl: add DVSEC config save/restore
2026-01-16 1:41 [PATCH v3 0/10] CXL reset support for Type 2 devices smadhavan
` (6 preceding siblings ...)
2026-01-16 1:41 ` [PATCH v3 7/10] cxl: add host cache flush and multi-function reset smadhavan
@ 2026-01-16 1:41 ` smadhavan
2026-01-16 1:41 ` [PATCH v3 9/10] PCI: save/restore CXL config around reset smadhavan
` (2 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: smadhavan @ 2026-01-16 1:41 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: smadhavan, vaslot, vsethi, sdonthineni, vidyas, mochs, jsequeira
From: Srirangan Madhavan <smadhavan@nvidia.com>
Save and restore CXL DVSEC control registers across reset with
CONFIG_LOCK handling so RWL fields are preserved when locked. This
maintains device policy and capability state across cxl_reset while
avoiding writes to locked fields.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
---
drivers/cxl/pci.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++
include/cxl/pci.h | 15 +++++++
2 files changed, 122 insertions(+)
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 5d2bb4431de3..9a9fab60f1e8 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -1161,6 +1161,113 @@ static int cxl_region_flush_host_cpu_caches(struct device *dev, void *data)
return 0;
}
+/*
+ * CXL DVSEC register save/restore
+ */
+static int cxl_save_dvsec_state(struct pci_dev *pdev,
+ struct cxl_type2_saved_state *state, int dvsec)
+{
+ int rc;
+
+ rc = pci_read_config_word(pdev, dvsec + CXL_DVSEC_CTRL_OFFSET,
+ &state->dvsec_ctrl);
+ if (rc)
+ return rc;
+
+ rc = pci_read_config_word(pdev, dvsec + CXL_DVSEC_CTRL2_OFFSET,
+ &state->dvsec_ctrl2);
+ return rc;
+}
+
+static int cxl_restore_dvsec_state(struct pci_dev *pdev,
+ const struct cxl_type2_saved_state *state,
+ int dvsec, bool config_locked)
+{
+ int rc;
+ u16 val_to_restore;
+
+ if (config_locked) {
+ u16 current_val;
+
+ rc = pci_read_config_word(pdev, dvsec + CXL_DVSEC_CTRL_OFFSET,
+ ¤t_val);
+ if (rc)
+ return rc;
+
+ val_to_restore = (current_val & CXL_DVSEC_CTRL_RWL_MASK) |
+ (state->dvsec_ctrl & ~CXL_DVSEC_CTRL_RWL_MASK);
+ } else {
+ val_to_restore = state->dvsec_ctrl;
+ }
+
+ rc = pci_write_config_word(pdev, dvsec + CXL_DVSEC_CTRL_OFFSET,
+ val_to_restore);
+ if (rc)
+ return rc;
+
+ rc = pci_write_config_word(pdev, dvsec + CXL_DVSEC_CTRL2_OFFSET,
+ state->dvsec_ctrl2);
+ return rc;
+}
+
+/**
+ * cxl_config_save_state - Save CXL configuration state
+ * @pdev: PCI device
+ * @state: Structure to store saved state
+ *
+ * Saves CXL DVSEC state before reset.
+ */
+int cxl_config_save_state(struct pci_dev *pdev,
+ struct cxl_type2_saved_state *state)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ int dvsec;
+
+ if (!cxlds || !state)
+ return -EINVAL;
+
+ memset(state, 0, sizeof(*state));
+
+ dvsec = cxlds->cxl_dvsec;
+ if (!dvsec)
+ return -ENODEV;
+
+ return cxl_save_dvsec_state(pdev, state, dvsec);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_config_save_state, "CXL");
+
+/**
+ * cxl_config_restore_state - Restore CXL configuration state
+ * @pdev: PCI device
+ * @state: Previously saved state
+ *
+ * Restores CXL DVSEC state after reset.
+ */
+int cxl_config_restore_state(struct pci_dev *pdev,
+ const struct cxl_type2_saved_state *state)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ bool config_locked;
+ int rc, dvsec;
+ u16 lock_reg;
+
+ if (!cxlds || !state)
+ return -EINVAL;
+
+ dvsec = cxlds->cxl_dvsec;
+ if (!dvsec)
+ return -ENODEV;
+
+ rc = pci_read_config_word(pdev, dvsec + CXL_DVSEC_LOCK_OFFSET, &lock_reg);
+ if (rc)
+ return rc;
+
+ config_locked = !!(lock_reg & CXL_DVSEC_LOCK_CONFIG_LOCK);
+
+ return cxl_restore_dvsec_state(pdev, state, dvsec, config_locked);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_config_restore_state, "CXL");
+
static int cxl_check_region_driver_bound(struct device *dev, void *data)
{
struct cxl_decoder *cxld = to_cxl_decoder(dev);
diff --git a/include/cxl/pci.h b/include/cxl/pci.h
index 71d8de5de948..2c629ded73cc 100644
--- a/include/cxl/pci.h
+++ b/include/cxl/pci.h
@@ -4,6 +4,18 @@
#ifndef __CXL_ACCEL_PCI_H
#define __CXL_ACCEL_PCI_H
+/* CXL Type 2 device state for save/restore across reset */
+struct cxl_type2_saved_state {
+ /* DVSEC registers */
+ u16 dvsec_ctrl;
+ u16 dvsec_ctrl2;
+};
+
+int cxl_config_save_state(struct pci_dev *pdev,
+ struct cxl_type2_saved_state *state);
+int cxl_config_restore_state(struct pci_dev *pdev,
+ const struct cxl_type2_saved_state *state);
+
/*
* See section 8.1 Configuration Space Registers in the CXL 2.0
* Specification. Names are taken straight from the specification with "CXL" and
@@ -23,6 +35,7 @@
#define CXL_DVSEC_CXL_RST_MEM_CLR_CAPABLE BIT(11)
#define CXL_DVSEC_CTRL_OFFSET 0xC
#define CXL_DVSEC_MEM_ENABLE BIT(2)
+#define CXL_DVSEC_CTRL_RWL_MASK 0x5FED
#define CXL_DVSEC_CTRL2_OFFSET 0x10
#define CXL_DVSEC_DISABLE_CACHING BIT(0)
#define CXL_DVSEC_INIT_CACHE_WBI BIT(1)
@@ -32,6 +45,8 @@
#define CXL_DVSEC_CACHE_INVALID BIT(0)
#define CXL_DVSEC_CXL_RST_COMPLETE BIT(1)
#define CXL_DVSEC_CXL_RESET_ERR BIT(2)
+#define CXL_DVSEC_LOCK_OFFSET 0x14
+#define CXL_DVSEC_LOCK_CONFIG_LOCK BIT(0)
#define CXL_DVSEC_RANGE_SIZE_HIGH(i) (0x18 + ((i) * 0x10))
#define CXL_DVSEC_RANGE_SIZE_LOW(i) (0x1C + ((i) * 0x10))
#define CXL_DVSEC_MEM_INFO_VALID BIT(0)
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 9/10] PCI: save/restore CXL config around reset
2026-01-16 1:41 [PATCH v3 0/10] CXL reset support for Type 2 devices smadhavan
` (7 preceding siblings ...)
2026-01-16 1:41 ` [PATCH v3 8/10] cxl: add DVSEC config save/restore smadhavan
@ 2026-01-16 1:41 ` smadhavan
2026-01-16 1:41 ` [PATCH v3 10/10] cxl: add HDM decoder and IDE save/restore smadhavan
2026-01-18 22:29 ` [PATCH v3 0/10] CXL reset support for Type 2 devices Alison Schofield
10 siblings, 0 replies; 16+ messages in thread
From: smadhavan @ 2026-01-16 1:41 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: smadhavan, vaslot, vsethi, sdonthineni, vidyas, mochs, jsequeira
From: Srirangan Madhavan <smadhavan@nvidia.com>
Save PCI and CXL configuration state before cxl_reset and restore it
after reset completes. This preserves DVSEC state alongside standard
PCI state and avoids losing reset-sensitive CXL configuration.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
---
drivers/pci/pci.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 83fd7e75a12e..705be8b079da 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4960,6 +4960,7 @@ static int cxl_reset_init(struct pci_dev *dev, u16 dvsec)
*/
static int cxl_reset(struct pci_dev *dev, bool probe)
{
+ struct cxl_type2_saved_state cxl_state;
u16 dvsec, reg;
int rc;
@@ -4985,6 +4986,11 @@ static int cxl_reset(struct pci_dev *dev, bool probe)
if (probe)
return 0;
+ pci_save_state(dev);
+ rc = cxl_config_save_state(dev, &cxl_state);
+ if (rc)
+ pci_warn(dev, "Failed to save CXL config state: %d\n", rc);
+
/*
* CXL-reset-specific preparation: validate memory offline,
* tear down regions, flush device caches.
@@ -5000,10 +5006,16 @@ static int cxl_reset(struct pci_dev *dev, bool probe)
if (rc)
goto out_cleanup;
+ pci_restore_state(dev);
+ rc = cxl_config_restore_state(dev, &cxl_state);
+ if (rc)
+ pci_warn(dev, "Failed to restore CXL config state: %d\n", rc);
+
cxl_reset_cleanup_device(dev);
return 0;
out_cleanup:
+ pci_restore_state(dev);
cxl_reset_cleanup_device(dev);
return rc;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 10/10] cxl: add HDM decoder and IDE save/restore
2026-01-16 1:41 [PATCH v3 0/10] CXL reset support for Type 2 devices smadhavan
` (8 preceding siblings ...)
2026-01-16 1:41 ` [PATCH v3 9/10] PCI: save/restore CXL config around reset smadhavan
@ 2026-01-16 1:41 ` smadhavan
2026-01-18 22:29 ` [PATCH v3 0/10] CXL reset support for Type 2 devices Alison Schofield
10 siblings, 0 replies; 16+ messages in thread
From: smadhavan @ 2026-01-16 1:41 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, ming.li,
rrichter, Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci
Cc: smadhavan, vaslot, vsethi, sdonthineni, vidyas, mochs, jsequeira
From: Srirangan Madhavan <smadhavan@nvidia.com>
Extend state save/restore to HDM decoder and IDE registers for Type 2
devices. The HDM/IDE blocks are located via the component register map,
then preserved across reset to retain decoder configuration and IDE
policy. This avoids losing HDM/IDE programming when cxl_reset is issued.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
---
drivers/cxl/core/regs.c | 7 ++
drivers/cxl/cxl.h | 4 ++
drivers/cxl/pci.c | 153 ++++++++++++++++++++++++++++++++++++++--
include/cxl/pci.h | 43 +++++++++++
4 files changed, 201 insertions(+), 6 deletions(-)
diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index ecdb22ae6952..76d6869d82ea 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -93,6 +93,12 @@ void cxl_probe_component_regs(struct device *dev, void __iomem *base,
length = CXL_RAS_CAPABILITY_LENGTH;
rmap = &map->ras;
break;
+ case CXL_CM_CAP_CAP_ID_IDE:
+ dev_dbg(dev, "found IDE capability (0x%x)\n",
+ offset);
+ length = CXL_IDE_CAPABILITY_LENGTH;
+ rmap = &map->ide;
+ break;
default:
dev_dbg(dev, "Unknown CM cap ID: %d (0x%x)\n", cap_id,
offset);
@@ -212,6 +218,7 @@ int cxl_map_component_regs(const struct cxl_register_map *map,
} mapinfo[] = {
{ &map->component_map.hdm_decoder, ®s->hdm_decoder },
{ &map->component_map.ras, ®s->ras },
+ { &map->component_map.ide, ®s->ide },
};
int i;
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index ba17fa86d249..a7a6b79755b3 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -39,8 +39,10 @@ extern const struct nvdimm_security_ops *cxl_security_ops;
#define CXL_CM_CAP_PTR_MASK GENMASK(31, 20)
#define CXL_CM_CAP_CAP_ID_RAS 0x2
+#define CXL_CM_CAP_CAP_ID_IDE 0x4
#define CXL_CM_CAP_CAP_ID_HDM 0x5
#define CXL_CM_CAP_CAP_HDM_VERSION 1
+#define CXL_IDE_CAPABILITY_LENGTH 0x20
/* HDM decoders CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure */
#define CXL_HDM_DECODER_CAP_OFFSET 0x0
@@ -214,6 +216,7 @@ struct cxl_regs {
struct_group_tagged(cxl_component_regs, component,
void __iomem *hdm_decoder;
void __iomem *ras;
+ void __iomem *ide;
);
/*
* Common set of CXL Device register block base pointers
@@ -256,6 +259,7 @@ struct cxl_reg_map {
struct cxl_component_reg_map {
struct cxl_reg_map hdm_decoder;
struct cxl_reg_map ras;
+ struct cxl_reg_map ide;
};
struct cxl_device_reg_map {
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 9a9fab60f1e8..f00bb542a7ee 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -963,7 +963,8 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev_dbg(&pdev->dev, "RAS registers not found\n");
rc = cxl_map_component_regs(&cxlds->reg_map, &cxlds->regs.component,
- BIT(CXL_CM_CAP_CAP_ID_RAS));
+ BIT(CXL_CM_CAP_CAP_ID_RAS) |
+ BIT(CXL_CM_CAP_CAP_ID_IDE));
if (rc)
dev_dbg(&pdev->dev, "Failed to map RAS capability.\n");
@@ -1210,18 +1211,126 @@ static int cxl_restore_dvsec_state(struct pci_dev *pdev,
return rc;
}
+/*
+ * CXL HDM Decoder register save/restore
+ */
+static int cxl_save_hdm_state(struct cxl_dev_state *cxlds,
+ struct cxl_type2_saved_state *state)
+{
+ void __iomem *hdm = cxlds->regs.hdm_decoder;
+ u32 cap, ctrl;
+ int i, count;
+
+ if (!hdm)
+ return 0;
+
+ cap = readl(hdm + CXL_HDM_DECODER_CAP_OFFSET);
+ count = cap & CXL_HDM_DECODER_COUNT_MASK;
+ count = min(count, CXL_MAX_DECODERS);
+
+ state->hdm_decoder_count = count;
+ state->hdm_global_ctrl = readl(hdm + CXL_HDM_DECODER_GLOBAL_CTRL_OFFSET);
+
+ for (i = 0; i < count; i++) {
+ struct cxl_hdm_decoder_state *d = &state->decoders[i];
+ u32 base_low, base_high, size_low, size_high;
+ u32 dpa_skip_low, dpa_skip_high;
+
+ base_low = readl(hdm + CXL_HDM_DECODER_BASE_LOW(i));
+ base_high = readl(hdm + CXL_HDM_DECODER_BASE_HIGH(i));
+ size_low = readl(hdm + CXL_HDM_DECODER_SIZE_LOW(i));
+ size_high = readl(hdm + CXL_HDM_DECODER_SIZE_HIGH(i));
+ ctrl = readl(hdm + CXL_HDM_DECODER_CTRL(i));
+ dpa_skip_low = readl(hdm + CXL_HDM_DECODER_DPA_SKIP_LOW(i));
+ dpa_skip_high = readl(hdm + CXL_HDM_DECODER_DPA_SKIP_HIGH(i));
+
+ d->base = ((u64)base_high << 32) | base_low;
+ d->size = ((u64)size_high << 32) | size_low;
+ d->ctrl = ctrl;
+ d->dpa_skip = ((u64)dpa_skip_high << 32) | dpa_skip_low;
+ d->enabled = !!(ctrl & CXL_HDM_DECODER_ENABLE);
+ }
+
+ return 0;
+}
+
+static int cxl_restore_hdm_state(struct cxl_dev_state *cxlds,
+ const struct cxl_type2_saved_state *state)
+{
+ void __iomem *hdm = cxlds->regs.hdm_decoder;
+ int i;
+
+ if (!hdm || state->hdm_decoder_count == 0)
+ return 0;
+
+ writel(state->hdm_global_ctrl, hdm + CXL_HDM_DECODER_GLOBAL_CTRL_OFFSET);
+
+ for (i = 0; i < state->hdm_decoder_count; i++) {
+ const struct cxl_hdm_decoder_state *d = &state->decoders[i];
+
+ writel((u32)d->base, hdm + CXL_HDM_DECODER_BASE_LOW(i));
+ writel((u32)(d->base >> 32), hdm + CXL_HDM_DECODER_BASE_HIGH(i));
+ writel((u32)d->size, hdm + CXL_HDM_DECODER_SIZE_LOW(i));
+ writel((u32)(d->size >> 32), hdm + CXL_HDM_DECODER_SIZE_HIGH(i));
+ writel(d->ctrl, hdm + CXL_HDM_DECODER_CTRL(i));
+ writel((u32)d->dpa_skip, hdm + CXL_HDM_DECODER_DPA_SKIP_LOW(i));
+ writel((u32)(d->dpa_skip >> 32), hdm + CXL_HDM_DECODER_DPA_SKIP_HIGH(i));
+ }
+
+ return 0;
+}
+
+/*
+ * CXL IDE register save/restore
+ */
+static int cxl_save_ide_state(struct cxl_dev_state *cxlds,
+ struct cxl_type2_saved_state *state)
+{
+ void __iomem *ide = cxlds->regs.ide;
+ u32 cap;
+
+ if (!ide)
+ return 0;
+
+ cap = readl(ide + CXL_IDE_CAP_OFFSET);
+ if (!(cap & CXL_IDE_CAP_CAPABLE))
+ return 0;
+
+ state->ide_cap = cap;
+ state->ide_ctrl = readl(ide + CXL_IDE_CTRL_OFFSET);
+ state->ide_key_refresh_time = readl(ide + CXL_IDE_KEY_REFRESH_TIME_CTRL_OFFSET);
+ state->ide_truncation_delay = readl(ide + CXL_IDE_TRUNCATION_DELAY_CTRL_OFFSET);
+
+ return 0;
+}
+
+static int cxl_restore_ide_state(struct cxl_dev_state *cxlds,
+ const struct cxl_type2_saved_state *state)
+{
+ void __iomem *ide = cxlds->regs.ide;
+
+ if (!ide || !(state->ide_cap & CXL_IDE_CAP_CAPABLE))
+ return 0;
+
+ writel(state->ide_ctrl, ide + CXL_IDE_CTRL_OFFSET);
+ writel(state->ide_key_refresh_time, ide + CXL_IDE_KEY_REFRESH_TIME_CTRL_OFFSET);
+ writel(state->ide_truncation_delay, ide + CXL_IDE_TRUNCATION_DELAY_CTRL_OFFSET);
+
+ return 0;
+}
+
/**
* cxl_config_save_state - Save CXL configuration state
* @pdev: PCI device
* @state: Structure to store saved state
*
- * Saves CXL DVSEC state before reset.
+ * Saves CXL DVSEC, HDM decoder, and IDE state before reset.
*/
int cxl_config_save_state(struct pci_dev *pdev,
struct cxl_type2_saved_state *state)
{
struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
- int dvsec;
+ int rc, dvsec;
if (!cxlds || !state)
return -EINVAL;
@@ -1232,7 +1341,23 @@ int cxl_config_save_state(struct pci_dev *pdev,
if (!dvsec)
return -ENODEV;
- return cxl_save_dvsec_state(pdev, state, dvsec);
+ rc = cxl_save_dvsec_state(pdev, state, dvsec);
+ if (rc)
+ return rc;
+
+ if (cxlds->regs.hdm_decoder) {
+ rc = cxl_save_hdm_state(cxlds, state);
+ if (rc)
+ pci_warn(pdev, "Failed to save HDM state: %d\n", rc);
+ }
+
+ if (cxlds->regs.ide) {
+ rc = cxl_save_ide_state(cxlds, state);
+ if (rc)
+ pci_warn(pdev, "Failed to save IDE state: %d\n", rc);
+ }
+
+ return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_config_save_state, "CXL");
@@ -1241,7 +1366,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_config_save_state, "CXL");
* @pdev: PCI device
* @state: Previously saved state
*
- * Restores CXL DVSEC state after reset.
+ * Restores CXL DVSEC, HDM decoder, and IDE state after reset.
*/
int cxl_config_restore_state(struct pci_dev *pdev,
const struct cxl_type2_saved_state *state)
@@ -1264,7 +1389,23 @@ int cxl_config_restore_state(struct pci_dev *pdev,
config_locked = !!(lock_reg & CXL_DVSEC_LOCK_CONFIG_LOCK);
- return cxl_restore_dvsec_state(pdev, state, dvsec, config_locked);
+ rc = cxl_restore_dvsec_state(pdev, state, dvsec, config_locked);
+ if (rc)
+ return rc;
+
+ if (cxlds->regs.hdm_decoder && state->hdm_decoder_count > 0) {
+ rc = cxl_restore_hdm_state(cxlds, state);
+ if (rc)
+ pci_warn(pdev, "Failed to restore HDM state: %d\n", rc);
+ }
+
+ if (cxlds->regs.ide && (state->ide_cap & CXL_IDE_CAP_CAPABLE)) {
+ rc = cxl_restore_ide_state(cxlds, state);
+ if (rc)
+ pci_warn(pdev, "Failed to restore IDE state: %d\n", rc);
+ }
+
+ return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_config_restore_state, "CXL");
diff --git a/include/cxl/pci.h b/include/cxl/pci.h
index 2c629ded73cc..9f2a9ad10d75 100644
--- a/include/cxl/pci.h
+++ b/include/cxl/pci.h
@@ -4,11 +4,33 @@
#ifndef __CXL_ACCEL_PCI_H
#define __CXL_ACCEL_PCI_H
+/* HDM Decoder state for save/restore */
+struct cxl_hdm_decoder_state {
+ u64 base;
+ u64 size;
+ u32 ctrl;
+ u64 dpa_skip;
+ bool enabled;
+};
+
+#define CXL_MAX_DECODERS 10
+
/* CXL Type 2 device state for save/restore across reset */
struct cxl_type2_saved_state {
/* DVSEC registers */
u16 dvsec_ctrl;
u16 dvsec_ctrl2;
+
+ /* HDM Decoder registers */
+ u32 hdm_decoder_count;
+ u32 hdm_global_ctrl;
+ struct cxl_hdm_decoder_state decoders[CXL_MAX_DECODERS];
+
+ /* IDE registers */
+ u32 ide_cap;
+ u32 ide_ctrl;
+ u32 ide_key_refresh_time;
+ u32 ide_truncation_delay;
};
int cxl_config_save_state(struct pci_dev *pdev,
@@ -58,6 +80,27 @@ int cxl_config_restore_state(struct pci_dev *pdev,
#define CXL_DVSEC_RANGE_MAX 2
+/* CXL HDM Decoder Capability Structure (Section 8.2.4.20) */
+#define CXL_HDM_DECODER_CAP_OFFSET 0x0
+#define CXL_HDM_DECODER_COUNT_MASK GENMASK(3, 0)
+#define CXL_HDM_DECODER_GLOBAL_CTRL_OFFSET 0x4
+#define CXL_HDM_DECODER_ENABLE BIT(1)
+/* CXL HDM Decoder n registers (Offset 20h*n + base) */
+#define CXL_HDM_DECODER_BASE_LOW(n) (0x10 + ((n) * 0x20))
+#define CXL_HDM_DECODER_BASE_HIGH(n) (0x14 + ((n) * 0x20))
+#define CXL_HDM_DECODER_SIZE_LOW(n) (0x18 + ((n) * 0x20))
+#define CXL_HDM_DECODER_SIZE_HIGH(n) (0x1C + ((n) * 0x20))
+#define CXL_HDM_DECODER_CTRL(n) (0x20 + ((n) * 0x20))
+#define CXL_HDM_DECODER_DPA_SKIP_LOW(n) (0x24 + ((n) * 0x20))
+#define CXL_HDM_DECODER_DPA_SKIP_HIGH(n) (0x28 + ((n) * 0x20))
+
+/* CXL IDE Capability Structure (Section 8.2.4.22) */
+#define CXL_IDE_CAP_OFFSET 0x00
+#define CXL_IDE_CAP_CAPABLE BIT(0)
+#define CXL_IDE_CTRL_OFFSET 0x04
+#define CXL_IDE_KEY_REFRESH_TIME_CTRL_OFFSET 0x18
+#define CXL_IDE_TRUNCATION_DELAY_CTRL_OFFSET 0x1C
+
/* CXL 2.0 8.1.4: Non-CXL Function Map DVSEC */
#define CXL_DVSEC_FUNCTION_MAP 2
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v3 0/10] CXL reset support for Type 2 devices
2026-01-16 1:41 [PATCH v3 0/10] CXL reset support for Type 2 devices smadhavan
` (9 preceding siblings ...)
2026-01-16 1:41 ` [PATCH v3 10/10] cxl: add HDM decoder and IDE save/restore smadhavan
@ 2026-01-18 22:29 ` Alison Schofield
2026-01-20 22:33 ` Srirangan Madhavan
[not found] ` <CY5PR12MB6226EE35D88E6F4442572D1CC389A@CY5PR12MB6226.namprd12.prod.outlook.com>
10 siblings, 2 replies; 16+ messages in thread
From: Alison Schofield @ 2026-01-18 22:29 UTC (permalink / raw)
To: smadhavan
Cc: dave, jonathan.cameron, dave.jiang, vishal.l.verma, ira.weiny,
dan.j.williams, bhelgaas, ming.li, rrichter,
Smita.KoralahalliChannabasappa, huaisheng.ye, linux-cxl,
linux-pci, vaslot, vsethi, sdonthineni, vidyas, mochs, jsequeira
On Fri, Jan 16, 2026 at 01:41:36AM +0000, smadhavan@nvidia.com wrote:
> From: Srirangan Madhavan <smadhavan@nvidia.com>
>
> Hi folks!
>
> This patch series introduces support for the CXL Reset method for CXL
> devices, implementing the reset procedure outlined in CXL Spec [1] v3.2,
> Sections 9.6 and 9.7.
Hi,
Seems something is missing from the set or a dependency not noted.
It stops compiling at Patch 8 cxl: add reset prepare and region teardown
-- Alison
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v3 0/10] CXL reset support for Type 2 devices
2026-01-18 22:29 ` [PATCH v3 0/10] CXL reset support for Type 2 devices Alison Schofield
@ 2026-01-20 22:33 ` Srirangan Madhavan
[not found] ` <CY5PR12MB6226EE35D88E6F4442572D1CC389A@CY5PR12MB6226.namprd12.prod.outlook.com>
1 sibling, 0 replies; 16+ messages in thread
From: Srirangan Madhavan @ 2026-01-20 22:33 UTC (permalink / raw)
To: Alison Schofield
Cc: dave@stgolabs.net, jonathan.cameron@huawei.com,
dave.jiang@intel.com, vishal.l.verma@intel.com,
ira.weiny@intel.com, dan.j.williams@intel.com,
bhelgaas@google.com, ming.li@zohomail.com, rrichter@amd.com,
Smita.KoralahalliChannabasappa@amd.com, huaisheng.ye@intel.com,
linux-cxl@vger.kernel.org, linux-pci@vger.kernel.org,
Vishal Aslot, Vikram Sethi, Shanker Donthineni, Vidya Sagar,
Matt Ochs, Jason Sequeira
Hi Alison,
Thank you for the heads‑up. I’ve respun the series as v4 and rebased it on pci/next as mentioned by the testbot. The v4 changes are limited to build‑fixes from the bot report + Reported‑by/Closes on the reset method patch. And the reproduce steps from testbot clear locally for me now.
In v4 & v3 , “reset prepare and region teardown” is patch 5 (not 8). If you still see a build failure at that point, could you share the exact error/log and the tree/config you’re using? I’ll take a look right away.
Thanks,
Srirangan
________________________________________
From: Alison Schofield <alison.schofield@intel.com>
Sent: Sunday, January 18, 2026 2:29 PM
To: Srirangan Madhavan
Cc: dave@stgolabs.net; jonathan.cameron@huawei.com; dave.jiang@intel.com; vishal.l.verma@intel.com; ira.weiny@intel.com; dan.j.williams@intel.com; bhelgaas@google.com; ming.li@zohomail.com; rrichter@amd.com; Smita.KoralahalliChannabasappa@amd.com; huaisheng.ye@intel.com; linux-cxl@vger.kernel.org; linux-pci@vger.kernel.org; Vishal Aslot; Vikram Sethi; Shanker Donthineni; Vidya Sagar; Matt Ochs; Jason Sequeira
Subject: Re: [PATCH v3 0/10] CXL reset support for Type 2 devices
External email: Use caution opening links or attachments
On Fri, Jan 16, 2026 at 01:41:36AM +0000, smadhavan@nvidia.com wrote:
> From: Srirangan Madhavan <smadhavan@nvidia.com>
>
> Hi folks!
>
> This patch series introduces support for the CXL Reset method for CXL
> devices, implementing the reset procedure outlined in CXL Spec [1] v3.2,
> Sections 9.6 and 9.7.
Hi,
Seems something is missing from the set or a dependency not noted.
It stops compiling at Patch 8 cxl: add reset prepare and region teardown
-- Alison
^ permalink raw reply [flat|nested] 16+ messages in thread[parent not found: <CY5PR12MB6226EE35D88E6F4442572D1CC389A@CY5PR12MB6226.namprd12.prod.outlook.com>]
* Re: [PATCH v3 0/10] CXL reset support for Type 2 devices
[not found] ` <CY5PR12MB6226EE35D88E6F4442572D1CC389A@CY5PR12MB6226.namprd12.prod.outlook.com>
@ 2026-01-21 0:30 ` Alison Schofield
0 siblings, 0 replies; 16+ messages in thread
From: Alison Schofield @ 2026-01-21 0:30 UTC (permalink / raw)
To: Srirangan Madhavan
Cc: dave@stgolabs.net, jonathan.cameron@huawei.com,
dave.jiang@intel.com, vishal.l.verma@intel.com,
ira.weiny@intel.com, dan.j.williams@intel.com,
bhelgaas@google.com, ming.li@zohomail.com, rrichter@amd.com,
Smita.KoralahalliChannabasappa@amd.com, huaisheng.ye@intel.com,
linux-cxl@vger.kernel.org, linux-pci@vger.kernel.org,
Vishal Aslot, Vikram Sethi, Shanker Donthineni, Vidya Sagar,
Matt Ochs, Jason Sequeira
On Tue, Jan 20, 2026 at 10:30:51PM +0000, Srirangan Madhavan wrote:
> Hi Alison,
>
> Thank you for the heads‑up. I’ve respun the series as v4 and rebased it on pci/next as mentioned by the testbot. The v4 changes are limited to build‑fixes from the bot report + Reported‑by/Closes on the reset method patch. And the reproduce steps from testbot clear locally for me now.
pci/next? Ah, that's different than what we typically do in drivers/cxl.
I was expecting a mainline base commit - like 6.19-rc6. Anyway v4 still
has conflicts w that. What is the dependency that is on pci/next? I can
see the impact, appended below, but pci/next has a slew of things since
6.19-rc1.
drivers/cxl/pci.c:1090:6: error: redefinition of ‘cxl_is_type2_device’
1090 | bool cxl_is_type2_device(struct pci_dev *pdev)
| ^~~~~~~~~~~~~~~~~~~
In file included from drivers/cxl/pci.c:11:
./include/linux/pci.h:1472:20: note: previous definition of ‘cxl_is_type2_device’ with type ‘bool(struct pci_dev *)’ {aka ‘_Bool(struct pci_dev *)’}
1472 | static inline bool cxl_is_type2_device(struct pci_dev *dev)
| ^~~~~~~~~~~~~~~~~~~
drivers/cxl/pci.c: In function ‘cxl_check_region_driver_bound’:
drivers/cxl/pci.c:1419:28: error: ‘cxl_region_rwsem’ undeclared (first use in this function); did you mean ‘cxl_region_ref’?
1419 | guard(rwsem_read)(&cxl_region_rwsem);
| ^~~~~~~~~~~~~~~~
| cxl_region_ref
drivers/cxl/pci.c:1419:28: note: each undeclared identifier is reported only once for each function it appears in
drivers/cxl/pci.c:1420:41: error: ‘struct cxl_region’ has no member named ‘driver’
1420 | if (cxld->region && cxld->region->driver)
| ^~
drivers/cxl/pci.c: In function ‘cxl_decoder_kill_region_iter’:
drivers/cxl/pci.c:1437:9: error: implicit declaration of function ‘cxl_decoder_kill_region_locked’; did you mean ‘cxl_decoder_kill_region_iter’? [-Werror=implicit-function-declaration]
1437 | cxl_decoder_kill_region_locked(cxled);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| cxl_decoder_kill_region_iter
drivers/cxl/pci.c: In function ‘cxl_region_flush_device_caches’:
drivers/cxl/pci.c:1504:53: error: ‘struct cxl_dev_state’ has no member named ‘pdev’; did you mean ‘dev’?
1504 | if (!target_cxlds || !target_cxlds->pdev)
| ^~~~
| dev
drivers/cxl/pci.c:1507:35: error: ‘struct cxl_dev_state’ has no member named ‘pdev’; did you mean ‘dev’?
1507 | if (target_cxlds->pdev != target_pdev)
| ^~~~
| dev
drivers/cxl/pci.c: In function ‘cxl_reset_prepare_memdev’:
drivers/cxl/pci.c:1548:21: error: ‘cxl_region_rwsem’ undeclared (first use in this function); did you mean ‘cxl_region_ref’?
1548 | down_write(&cxl_region_rwsem);
| ^~~~~~~~~~~~~~~~
| cxl_region_ref
In file included from ./include/linux/spinlock.h:63,
from ./include/linux/sched.h:37,
from ./include/linux/percpu.h:12,
from ./arch/x86/include/asm/msr.h:16,
from ./arch/x86/include/asm/tsc.h:11,
from ./arch/x86/include/asm/timex.h:6,
from ./include/linux/timex.h:67,
from ./include/linux/time32.h:13,
from ./include/linux/time.h:60,
from ./include/linux/stat.h:19,
from ./include/linux/module.h:13,
from drivers/cxl/pci.c:6:
drivers/cxl/pci.c: In function ‘cxl_reset_cleanup_memdev’:
drivers/cxl/pci.c:1585:35: error: ‘cxl_region_rwsem’ undeclared (first use in this function); did you mean ‘cxl_region_ref’?
1585 | if (lockdep_is_held_type(&cxl_region_rwsem, -1))
| ^~~~~~~~~~~~~~~~
./include/linux/lockdep.h:253:61: note: in definition of macro ‘lockdep_is_held_type’
253 | fine lockdep_is_held_type(lock, r) lock_is_held_type(&(lock)->dep_map, (r))
| ^~~~
drivers/cxl/pci.c: At top level:
drivers/cxl/pci.c:1665:5: error: redefinition of ‘cxl_reset_prepare_device’
1665 | int cxl_reset_prepare_device(struct pci_dev *pdev)
| ^~~~~~~~~~~~~~~~~~~~~~~~
./include/linux/pci.h:1477:19: note: previous definition of ‘cxl_reset_prepare_device’ with type ‘int(struct pci_dev *)’
1477 | static inline int cxl_reset_prepare_device(struct pci_dev *pdev)
| ^~~~~~~~~~~~~~~~~~~~~~~~
drivers/cxl/pci.c:1696:6: error: redefinition of ‘cxl_reset_cleanup_device’
1696 | void cxl_reset_cleanup_device(struct pci_dev *pdev)
| ^~~~~~~~~~~~~~~~~~~~~~~~
./include/linux/pci.h:1482:20: note: previous definition of ‘cxl_reset_cleanup_device’ with type ‘void(struct pci_dev *)’
1482 | static inline void cxl_reset_cleanup_device(struct pci_dev *pdev)
| ^~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
^ permalink raw reply [flat|nested] 16+ messages in thread