* [PATCH v12 01/25] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-25 22:34 ` [PATCH v12 02/25] cxl/pci: Remove unnecessary CXL RCH " Terry Bowman
` (23 subsequent siblings)
24 siblings, 0 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
The CXL driver's cxl_handle_endpoint_cor_ras()/cxl_handle_endpoint_ras()
are unnecessary helper functions used only for Endpoints. Remove these
functions as they are not common for all CXL devices and do not provide
value for EP handling.
Rename __cxl_handle_ras to cxl_handle_ras() and __cxl_handle_cor_ras()
to cxl_handle_cor_ras().
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
---
Changes in v11->v12:
- Added Dave Jiang's review by
- Moved to front of series
Changes in v10->v11:
- None
---
drivers/cxl/core/pci.c | 26 ++++++++------------------
1 file changed, 8 insertions(+), 18 deletions(-)
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 18825e1505d6..078e9e5651e1 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -711,8 +711,8 @@ void read_cdat_data(struct cxl_port *port)
}
EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
-static void __cxl_handle_cor_ras(struct cxl_dev_state *cxlds,
- void __iomem *ras_base)
+static void cxl_handle_cor_ras(struct cxl_dev_state *cxlds,
+ void __iomem *ras_base)
{
void __iomem *addr;
u32 status;
@@ -728,11 +728,6 @@ static void __cxl_handle_cor_ras(struct cxl_dev_state *cxlds,
}
}
-static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)
-{
- return __cxl_handle_cor_ras(cxlds, cxlds->regs.ras);
-}
-
/* CXL spec rev3.0 8.2.4.16.1 */
static void header_log_copy(void __iomem *ras_base, u32 *log)
{
@@ -754,8 +749,8 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
* Log the state of the RAS status registers and prepare them to log the
* next error status. Return 1 if reset needed.
*/
-static bool __cxl_handle_ras(struct cxl_dev_state *cxlds,
- void __iomem *ras_base)
+static bool cxl_handle_ras(struct cxl_dev_state *cxlds,
+ void __iomem *ras_base)
{
u32 hl[CXL_HEADERLOG_SIZE_U32];
void __iomem *addr;
@@ -788,11 +783,6 @@ static bool __cxl_handle_ras(struct cxl_dev_state *cxlds,
return true;
}
-static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
-{
- return __cxl_handle_ras(cxlds, cxlds->regs.ras);
-}
-
#ifdef CONFIG_PCIEAER_CXL
static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
@@ -871,13 +861,13 @@ EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
struct cxl_dport *dport)
{
- return __cxl_handle_cor_ras(cxlds, dport->regs.ras);
+ return cxl_handle_cor_ras(cxlds, dport->regs.ras);
}
static bool cxl_handle_rdport_ras(struct cxl_dev_state *cxlds,
struct cxl_dport *dport)
{
- return __cxl_handle_ras(cxlds, dport->regs.ras);
+ return cxl_handle_ras(cxlds, dport->regs.ras);
}
/*
@@ -974,7 +964,7 @@ void cxl_cor_error_detected(struct pci_dev *pdev)
if (cxlds->rcd)
cxl_handle_rdport_errors(cxlds);
- cxl_handle_endpoint_cor_ras(cxlds);
+ cxl_handle_cor_ras(cxlds, cxlds->regs.ras);
}
}
EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
@@ -1003,7 +993,7 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
* chance the situation is recoverable dump the status of the RAS
* capability registers and bounce the active state of the memdev.
*/
- ue = cxl_handle_endpoint_ras(cxlds);
+ ue = cxl_handle_ras(cxlds, cxlds->regs.ras);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* [PATCH v12 02/25] cxl/pci: Remove unnecessary CXL RCH handling helper functions
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
2025-09-25 22:34 ` [PATCH v12 01/25] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-10-01 15:09 ` Jonathan Cameron
2025-09-25 22:34 ` [PATCH v12 03/25] cxl: Remove ifdef blocks of CONFIG_PCIEAER_CXL from core/pci.c Terry Bowman
` (22 subsequent siblings)
24 siblings, 1 reply; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
cxl_handle_rdport_cor_ras() and cxl_handle_rdport_ras() are specific
to Restricted CXL Host (RCH) handling. Improve readability and
maintainability by replacing these and instead using the common
cxl_handle_cor_ras() and cxl_handle_ras() functions.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
---
Changes in v11->v12:
- Add reviewed-by for Alejandro & Dave Jiang
- Moved to front of series
Changes in v10->v11:
- New patch
---
drivers/cxl/core/pci.c | 16 ++--------------
1 file changed, 2 insertions(+), 14 deletions(-)
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 078e9e5651e1..3fb9462954da 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -858,18 +858,6 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
}
EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
-static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
- struct cxl_dport *dport)
-{
- return cxl_handle_cor_ras(cxlds, dport->regs.ras);
-}
-
-static bool cxl_handle_rdport_ras(struct cxl_dev_state *cxlds,
- struct cxl_dport *dport)
-{
- return cxl_handle_ras(cxlds, dport->regs.ras);
-}
-
/*
* Copy the AER capability registers using 32 bit read accesses.
* This is necessary because RCRB AER capability is MMIO mapped. Clear the
@@ -939,9 +927,9 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
pci_print_aer(pdev, severity, &aer_regs);
if (severity == AER_CORRECTABLE)
- cxl_handle_rdport_cor_ras(cxlds, dport);
+ cxl_handle_cor_ras(cxlds, dport->regs.ras);
else
- cxl_handle_rdport_ras(cxlds, dport);
+ cxl_handle_ras(cxlds, dport->regs.ras);
}
#else
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 02/25] cxl/pci: Remove unnecessary CXL RCH handling helper functions
2025-09-25 22:34 ` [PATCH v12 02/25] cxl/pci: Remove unnecessary CXL RCH " Terry Bowman
@ 2025-10-01 15:09 ` Jonathan Cameron
0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Cameron @ 2025-10-01 15:09 UTC (permalink / raw)
To: Terry Bowman
Cc: dave, dave.jiang, alison.schofield, dan.j.williams, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, linux-cxl,
alucerop, ira.weiny, linux-kernel, linux-pci
On Thu, 25 Sep 2025 17:34:17 -0500
Terry Bowman <terry.bowman@amd.com> wrote:
> cxl_handle_rdport_cor_ras() and cxl_handle_rdport_ras() are specific
> to Restricted CXL Host (RCH) handling. Improve readability and
> maintainability by replacing these and instead using the common
> cxl_handle_cor_ras() and cxl_handle_ras() functions.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Alejandro Lucero <alucerop@amd.com>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 03/25] cxl: Remove ifdef blocks of CONFIG_PCIEAER_CXL from core/pci.c
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
2025-09-25 22:34 ` [PATCH v12 01/25] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions Terry Bowman
2025-09-25 22:34 ` [PATCH v12 02/25] cxl/pci: Remove unnecessary CXL RCH " Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-10-03 20:11 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 04/25] CXL/AER: Remove CONFIG_PCIEAER_CXL and replace with CONFIG_CXL_RAS Terry Bowman
` (21 subsequent siblings)
24 siblings, 1 reply; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
From: Dave Jiang <dave.jiang@intel.com>
Create new config CONFIG_CXL_RAS and put all CXL RAS items behind
the config. The config will depend on CPER and PCIE AER to build.
Move the related RAS code from core/pci.c to core/ras.c.
Cc: Robert Richter <rrichter@amd.com>
Cc: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Joshua Hahn <joshua.hahnjy@gmail.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
Changes in v11->v12:
- None
Changes in v10->v11:
- New patch
- Updated by Terry Bowman to use (ACPI_APEI_GHES && PCIEAER_CXL) dependency
in Kconfig. Otherwise checks will be reauired for CONFIG_PCIEAER because
AER driver functions are called.
---
drivers/cxl/Kconfig | 3 +
drivers/cxl/core/Makefile | 2 +-
drivers/cxl/core/core.h | 12 ++
drivers/cxl/core/pci.c | 297 --------------------------------------
drivers/cxl/core/ras.c | 289 +++++++++++++++++++++++++++++++++++++
drivers/cxl/cxl.h | 8 -
drivers/cxl/cxlpci.h | 16 ++
tools/testing/cxl/Kbuild | 2 +-
8 files changed, 322 insertions(+), 307 deletions(-)
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 48b7314afdb8..9246f734e6ca 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -233,4 +233,7 @@ config CXL_MCE
def_bool y
depends on X86_MCE && MEMORY_FAILURE
+config CXL_RAS
+ def_bool y
+ depends on ACPI_APEI_GHES && PCIEAER_CXL && CXL_PCI
endif
diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile
index 5ad8fef210b5..b2930cc54f8b 100644
--- a/drivers/cxl/core/Makefile
+++ b/drivers/cxl/core/Makefile
@@ -14,9 +14,9 @@ cxl_core-y += pci.o
cxl_core-y += hdm.o
cxl_core-y += pmu.o
cxl_core-y += cdat.o
-cxl_core-y += ras.o
cxl_core-$(CONFIG_TRACING) += trace.o
cxl_core-$(CONFIG_CXL_REGION) += region.o
cxl_core-$(CONFIG_CXL_MCE) += mce.o
cxl_core-$(CONFIG_CXL_FEATURES) += features.o
cxl_core-$(CONFIG_CXL_EDAC_MEM_FEATURES) += edac.o
+cxl_core-$(CONFIG_CXL_RAS) += ras.o
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 1fb66132b777..9f4eb7e2feba 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -144,8 +144,20 @@ int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c);
int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
struct access_coordinate *c);
+#ifdef CONFIG_CXL_RAS
int cxl_ras_init(void);
void cxl_ras_exit(void);
+#else
+static inline int cxl_ras_init(void)
+{
+ return 0;
+}
+
+static inline void cxl_ras_exit(void)
+{
+}
+#endif // CONFIG_CXL_RAS
+
int cxl_gpf_port_setup(struct cxl_dport *dport);
struct cxl_hdm;
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 3fb9462954da..a009a51cb0de 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -6,7 +6,6 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/pci-doe.h>
-#include <linux/aer.h>
#include <cxlpci.h>
#include <cxlmem.h>
#include <cxl.h>
@@ -711,302 +710,6 @@ void read_cdat_data(struct cxl_port *port)
}
EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
-static void cxl_handle_cor_ras(struct cxl_dev_state *cxlds,
- void __iomem *ras_base)
-{
- void __iomem *addr;
- u32 status;
-
- if (!ras_base)
- return;
-
- addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
- status = readl(addr);
- if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
- writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
- trace_cxl_aer_correctable_error(cxlds->cxlmd, status);
- }
-}
-
-/* CXL spec rev3.0 8.2.4.16.1 */
-static void header_log_copy(void __iomem *ras_base, u32 *log)
-{
- void __iomem *addr;
- u32 *log_addr;
- int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32);
-
- addr = ras_base + CXL_RAS_HEADER_LOG_OFFSET;
- log_addr = log;
-
- for (i = 0; i < log_u32_size; i++) {
- *log_addr = readl(addr);
- log_addr++;
- addr += sizeof(u32);
- }
-}
-
-/*
- * Log the state of the RAS status registers and prepare them to log the
- * next error status. Return 1 if reset needed.
- */
-static bool cxl_handle_ras(struct cxl_dev_state *cxlds,
- void __iomem *ras_base)
-{
- u32 hl[CXL_HEADERLOG_SIZE_U32];
- void __iomem *addr;
- u32 status;
- u32 fe;
-
- if (!ras_base)
- return false;
-
- addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
- status = readl(addr);
- if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
- return false;
-
- /* If multiple errors, log header points to first error from ctrl reg */
- if (hweight32(status) > 1) {
- void __iomem *rcc_addr =
- ras_base + CXL_RAS_CAP_CONTROL_OFFSET;
-
- fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK,
- readl(rcc_addr)));
- } else {
- fe = status;
- }
-
- header_log_copy(ras_base, hl);
- trace_cxl_aer_uncorrectable_error(cxlds->cxlmd, status, fe, hl);
- writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
-
- return true;
-}
-
-#ifdef CONFIG_PCIEAER_CXL
-
-static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
-{
- resource_size_t aer_phys;
- struct device *host;
- u16 aer_cap;
-
- aer_cap = cxl_rcrb_to_aer(dport->dport_dev, dport->rcrb.base);
- if (aer_cap) {
- host = dport->reg_map.host;
- aer_phys = aer_cap + dport->rcrb.base;
- dport->regs.dport_aer = devm_cxl_iomap_block(host, aer_phys,
- sizeof(struct aer_capability_regs));
- }
-}
-
-static void cxl_dport_map_ras(struct cxl_dport *dport)
-{
- struct cxl_register_map *map = &dport->reg_map;
- struct device *dev = dport->dport_dev;
-
- if (!map->component_map.ras.valid)
- dev_dbg(dev, "RAS registers not found\n");
- else if (cxl_map_component_regs(map, &dport->regs.component,
- BIT(CXL_CM_CAP_CAP_ID_RAS)))
- dev_dbg(dev, "Failed to map RAS capability.\n");
-}
-
-static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
-{
- void __iomem *aer_base = dport->regs.dport_aer;
- u32 aer_cmd_mask, aer_cmd;
-
- if (!aer_base)
- return;
-
- /*
- * Disable RCH root port command interrupts.
- * CXL 3.0 12.2.1.1 - RCH Downstream Port-detected Errors
- *
- * This sequence may not be necessary. CXL spec states disabling
- * the root cmd register's interrupts is required. But, PCI spec
- * shows these are disabled by default on reset.
- */
- aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
- PCI_ERR_ROOT_CMD_NONFATAL_EN |
- PCI_ERR_ROOT_CMD_FATAL_EN);
- aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
- aer_cmd &= ~aer_cmd_mask;
- writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
-}
-
-/**
- * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
- * @dport: the cxl_dport that needs to be initialized
- * @host: host device for devm operations
- */
-void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
-{
- dport->reg_map.host = host;
- cxl_dport_map_ras(dport);
-
- if (dport->rch) {
- struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev);
-
- if (!host_bridge->native_aer)
- return;
-
- cxl_dport_map_rch_aer(dport);
- cxl_disable_rch_root_ints(dport);
- }
-}
-EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
-
-/*
- * Copy the AER capability registers using 32 bit read accesses.
- * This is necessary because RCRB AER capability is MMIO mapped. Clear the
- * status after copying.
- *
- * @aer_base: base address of AER capability block in RCRB
- * @aer_regs: destination for copying AER capability
- */
-static bool cxl_rch_get_aer_info(void __iomem *aer_base,
- struct aer_capability_regs *aer_regs)
-{
- int read_cnt = sizeof(struct aer_capability_regs) / sizeof(u32);
- u32 *aer_regs_buf = (u32 *)aer_regs;
- int n;
-
- if (!aer_base)
- return false;
-
- /* Use readl() to guarantee 32-bit accesses */
- for (n = 0; n < read_cnt; n++)
- aer_regs_buf[n] = readl(aer_base + n * sizeof(u32));
-
- writel(aer_regs->uncor_status, aer_base + PCI_ERR_UNCOR_STATUS);
- writel(aer_regs->cor_status, aer_base + PCI_ERR_COR_STATUS);
-
- return true;
-}
-
-/* Get AER severity. Return false if there is no error. */
-static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,
- int *severity)
-{
- if (aer_regs->uncor_status & ~aer_regs->uncor_mask) {
- if (aer_regs->uncor_status & PCI_ERR_ROOT_FATAL_RCV)
- *severity = AER_FATAL;
- else
- *severity = AER_NONFATAL;
- return true;
- }
-
- if (aer_regs->cor_status & ~aer_regs->cor_mask) {
- *severity = AER_CORRECTABLE;
- return true;
- }
-
- return false;
-}
-
-static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
-{
- struct pci_dev *pdev = to_pci_dev(cxlds->dev);
- struct aer_capability_regs aer_regs;
- struct cxl_dport *dport;
- int severity;
-
- struct cxl_port *port __free(put_cxl_port) =
- cxl_pci_find_port(pdev, &dport);
- if (!port)
- return;
-
- if (!cxl_rch_get_aer_info(dport->regs.dport_aer, &aer_regs))
- return;
-
- if (!cxl_rch_get_aer_severity(&aer_regs, &severity))
- return;
-
- pci_print_aer(pdev, severity, &aer_regs);
-
- if (severity == AER_CORRECTABLE)
- cxl_handle_cor_ras(cxlds, dport->regs.ras);
- else
- cxl_handle_ras(cxlds, dport->regs.ras);
-}
-
-#else
-static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { }
-#endif
-
-void cxl_cor_error_detected(struct pci_dev *pdev)
-{
- struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
- struct device *dev = &cxlds->cxlmd->dev;
-
- scoped_guard(device, dev) {
- if (!dev->driver) {
- dev_warn(&pdev->dev,
- "%s: memdev disabled, abort error handling\n",
- dev_name(dev));
- return;
- }
-
- if (cxlds->rcd)
- cxl_handle_rdport_errors(cxlds);
-
- cxl_handle_cor_ras(cxlds, cxlds->regs.ras);
- }
-}
-EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
-
-pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
- pci_channel_state_t state)
-{
- struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
- struct cxl_memdev *cxlmd = cxlds->cxlmd;
- struct device *dev = &cxlmd->dev;
- bool ue;
-
- scoped_guard(device, dev) {
- if (!dev->driver) {
- dev_warn(&pdev->dev,
- "%s: memdev disabled, abort error handling\n",
- dev_name(dev));
- return PCI_ERS_RESULT_DISCONNECT;
- }
-
- if (cxlds->rcd)
- cxl_handle_rdport_errors(cxlds);
- /*
- * A frozen channel indicates an impending reset which is fatal to
- * CXL.mem operation, and will likely crash the system. On the off
- * chance the situation is recoverable dump the status of the RAS
- * capability registers and bounce the active state of the memdev.
- */
- ue = cxl_handle_ras(cxlds, cxlds->regs.ras);
- }
-
-
- switch (state) {
- case pci_channel_io_normal:
- if (ue) {
- device_release_driver(dev);
- return PCI_ERS_RESULT_NEED_RESET;
- }
- return PCI_ERS_RESULT_CAN_RECOVER;
- case pci_channel_io_frozen:
- dev_warn(&pdev->dev,
- "%s: frozen state error detected, disable CXL.mem\n",
- dev_name(dev));
- device_release_driver(dev);
- return PCI_ERS_RESULT_NEED_RESET;
- case pci_channel_io_perm_failure:
- dev_warn(&pdev->dev,
- "failure state error detected, request disconnect\n");
- return PCI_ERS_RESULT_DISCONNECT;
- }
- return PCI_ERS_RESULT_NEED_RESET;
-}
-EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL");
-
static int cxl_flit_size(struct pci_dev *pdev)
{
if (cxl_pci_flit_256(pdev))
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 2731ba3a0799..0875ce8116ff 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -5,6 +5,7 @@
#include <linux/aer.h>
#include <cxl/event.h>
#include <cxlmem.h>
+#include <cxlpci.h>
#include "trace.h"
static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
@@ -124,3 +125,291 @@ void cxl_ras_exit(void)
cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work);
cancel_work_sync(&cxl_cper_prot_err_work);
}
+
+static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
+{
+ resource_size_t aer_phys;
+ struct device *host;
+ u16 aer_cap;
+
+ aer_cap = cxl_rcrb_to_aer(dport->dport_dev, dport->rcrb.base);
+ if (aer_cap) {
+ host = dport->reg_map.host;
+ aer_phys = aer_cap + dport->rcrb.base;
+ dport->regs.dport_aer = devm_cxl_iomap_block(host, aer_phys,
+ sizeof(struct aer_capability_regs));
+ }
+}
+
+static void cxl_dport_map_ras(struct cxl_dport *dport)
+{
+ struct cxl_register_map *map = &dport->reg_map;
+ struct device *dev = dport->dport_dev;
+
+ if (!map->component_map.ras.valid)
+ dev_dbg(dev, "RAS registers not found\n");
+ else if (cxl_map_component_regs(map, &dport->regs.component,
+ BIT(CXL_CM_CAP_CAP_ID_RAS)))
+ dev_dbg(dev, "Failed to map RAS capability.\n");
+}
+
+static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
+{
+ void __iomem *aer_base = dport->regs.dport_aer;
+ u32 aer_cmd_mask, aer_cmd;
+
+ if (!aer_base)
+ return;
+
+ /*
+ * Disable RCH root port command interrupts.
+ * CXL 3.0 12.2.1.1 - RCH Downstream Port-detected Errors
+ *
+ * This sequence may not be necessary. CXL spec states disabling
+ * the root cmd register's interrupts is required. But, PCI spec
+ * shows these are disabled by default on reset.
+ */
+ aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
+ PCI_ERR_ROOT_CMD_NONFATAL_EN |
+ PCI_ERR_ROOT_CMD_FATAL_EN);
+ aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
+ aer_cmd &= ~aer_cmd_mask;
+ writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
+}
+
+
+/**
+ * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
+ * @dport: the cxl_dport that needs to be initialized
+ * @host: host device for devm operations
+ */
+void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
+{
+ dport->reg_map.host = host;
+ cxl_dport_map_ras(dport);
+
+ if (dport->rch) {
+ struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev);
+
+ if (!host_bridge->native_aer)
+ return;
+
+ cxl_dport_map_rch_aer(dport);
+ cxl_disable_rch_root_ints(dport);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
+
+static void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base)
+{
+ void __iomem *addr;
+ u32 status;
+
+ if (!ras_base)
+ return;
+
+ addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
+ status = readl(addr);
+ if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
+ writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
+ trace_cxl_aer_correctable_error(cxlds->cxlmd, status);
+ }
+}
+
+/* CXL spec rev3.0 8.2.4.16.1 */
+static void header_log_copy(void __iomem *ras_base, u32 *log)
+{
+ void __iomem *addr;
+ u32 *log_addr;
+ int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32);
+
+ addr = ras_base + CXL_RAS_HEADER_LOG_OFFSET;
+ log_addr = log;
+
+ for (i = 0; i < log_u32_size; i++) {
+ *log_addr = readl(addr);
+ log_addr++;
+ addr += sizeof(u32);
+ }
+}
+
+/*
+ * Log the state of the RAS status registers and prepare them to log the
+ * next error status. Return 1 if reset needed.
+ */
+static bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base)
+{
+ u32 hl[CXL_HEADERLOG_SIZE_U32];
+ void __iomem *addr;
+ u32 status;
+ u32 fe;
+
+ if (!ras_base)
+ return false;
+
+ addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
+ status = readl(addr);
+ if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
+ return false;
+
+ /* If multiple errors, log header points to first error from ctrl reg */
+ if (hweight32(status) > 1) {
+ void __iomem *rcc_addr =
+ ras_base + CXL_RAS_CAP_CONTROL_OFFSET;
+
+ fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK,
+ readl(rcc_addr)));
+ } else {
+ fe = status;
+ }
+
+ header_log_copy(ras_base, hl);
+ trace_cxl_aer_uncorrectable_error(cxlds->cxlmd, status, fe, hl);
+ writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
+
+ return true;
+}
+
+/*
+ * Copy the AER capability registers using 32 bit read accesses.
+ * This is necessary because RCRB AER capability is MMIO mapped. Clear the
+ * status after copying.
+ *
+ * @aer_base: base address of AER capability block in RCRB
+ * @aer_regs: destination for copying AER capability
+ */
+static bool cxl_rch_get_aer_info(void __iomem *aer_base,
+ struct aer_capability_regs *aer_regs)
+{
+ int read_cnt = sizeof(struct aer_capability_regs) / sizeof(u32);
+ u32 *aer_regs_buf = (u32 *)aer_regs;
+ int n;
+
+ if (!aer_base)
+ return false;
+
+ /* Use readl() to guarantee 32-bit accesses */
+ for (n = 0; n < read_cnt; n++)
+ aer_regs_buf[n] = readl(aer_base + n * sizeof(u32));
+
+ writel(aer_regs->uncor_status, aer_base + PCI_ERR_UNCOR_STATUS);
+ writel(aer_regs->cor_status, aer_base + PCI_ERR_COR_STATUS);
+
+ return true;
+}
+
+/* Get AER severity. Return false if there is no error. */
+static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,
+ int *severity)
+{
+ if (aer_regs->uncor_status & ~aer_regs->uncor_mask) {
+ if (aer_regs->uncor_status & PCI_ERR_ROOT_FATAL_RCV)
+ *severity = AER_FATAL;
+ else
+ *severity = AER_NONFATAL;
+ return true;
+ }
+
+ if (aer_regs->cor_status & ~aer_regs->cor_mask) {
+ *severity = AER_CORRECTABLE;
+ return true;
+ }
+
+ return false;
+}
+
+static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
+{
+ struct pci_dev *pdev = to_pci_dev(cxlds->dev);
+ struct aer_capability_regs aer_regs;
+ struct cxl_dport *dport;
+ int severity;
+
+ struct cxl_port *port __free(put_cxl_port) =
+ cxl_pci_find_port(pdev, &dport);
+ if (!port)
+ return;
+
+ if (!cxl_rch_get_aer_info(dport->regs.dport_aer, &aer_regs))
+ return;
+
+ if (!cxl_rch_get_aer_severity(&aer_regs, &severity))
+ return;
+
+ pci_print_aer(pdev, severity, &aer_regs);
+ if (severity == AER_CORRECTABLE)
+ cxl_handle_cor_ras(cxlds, dport->regs.ras);
+ else
+ cxl_handle_ras(cxlds, dport->regs.ras);
+}
+
+void cxl_cor_error_detected(struct pci_dev *pdev)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ struct device *dev = &cxlds->cxlmd->dev;
+
+ scoped_guard(device, dev) {
+ if (!dev->driver) {
+ dev_warn(&pdev->dev,
+ "%s: memdev disabled, abort error handling\n",
+ dev_name(dev));
+ return;
+ }
+
+ if (cxlds->rcd)
+ cxl_handle_rdport_errors(cxlds);
+
+ cxl_handle_cor_ras(cxlds, cxlds->regs.ras);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
+
+pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ struct cxl_memdev *cxlmd = cxlds->cxlmd;
+ struct device *dev = &cxlmd->dev;
+ bool ue;
+
+ scoped_guard(device, dev) {
+ if (!dev->driver) {
+ dev_warn(&pdev->dev,
+ "%s: memdev disabled, abort error handling\n",
+ dev_name(dev));
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ if (cxlds->rcd)
+ cxl_handle_rdport_errors(cxlds);
+ /*
+ * A frozen channel indicates an impending reset which is fatal to
+ * CXL.mem operation, and will likely crash the system. On the off
+ * chance the situation is recoverable dump the status of the RAS
+ * capability registers and bounce the active state of the memdev.
+ */
+ ue = cxl_handle_ras(cxlds, cxlds->regs.ras);
+ }
+
+
+ switch (state) {
+ case pci_channel_io_normal:
+ if (ue) {
+ device_release_driver(dev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ dev_warn(&pdev->dev,
+ "%s: frozen state error detected, disable CXL.mem\n",
+ dev_name(dev));
+ device_release_driver(dev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ dev_warn(&pdev->dev,
+ "failure state error detected, request disconnect\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL");
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 231ddccf8977..259ed4b676e1 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -776,14 +776,6 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
struct device *dport_dev, int port_id,
resource_size_t rcrb);
-#ifdef CONFIG_PCIEAER_CXL
-void cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport);
-void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
-#else
-static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
- struct device *host) { }
-#endif
-
struct cxl_decoder *to_cxl_decoder(struct device *dev);
struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev);
struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev);
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 7ae621e618e7..970e84cf49e9 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -130,7 +130,23 @@ static inline bool cxl_pci_flit_256(struct pci_dev *pdev)
int devm_cxl_port_enumerate_dports(struct cxl_port *port);
struct cxl_dev_state;
void read_cdat_data(struct cxl_port *port);
+
+#ifdef CONFIG_CXL_RAS
void cxl_cor_error_detected(struct pci_dev *pdev);
pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
pci_channel_state_t state);
+void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
+#else
+static inline void cxl_cor_error_detected(struct pci_dev *pdev) { }
+
+static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ return PCI_ERS_RESULT_NONE;
+}
+
+static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
+ struct device *host) { }
+#endif
+
#endif /* __CXL_PCI_H__ */
diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild
index 0d5ce4b74b9f..927fbb6c061f 100644
--- a/tools/testing/cxl/Kbuild
+++ b/tools/testing/cxl/Kbuild
@@ -58,12 +58,12 @@ cxl_core-y += $(CXL_CORE_SRC)/pci.o
cxl_core-y += $(CXL_CORE_SRC)/hdm.o
cxl_core-y += $(CXL_CORE_SRC)/pmu.o
cxl_core-y += $(CXL_CORE_SRC)/cdat.o
-cxl_core-y += $(CXL_CORE_SRC)/ras.o
cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o
cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o
cxl_core-$(CONFIG_CXL_MCE) += $(CXL_CORE_SRC)/mce.o
cxl_core-$(CONFIG_CXL_FEATURES) += $(CXL_CORE_SRC)/features.o
cxl_core-$(CONFIG_CXL_EDAC_MEM_FEATURES) += $(CXL_CORE_SRC)/edac.o
+cxl_core-$(CONFIG_CXL_RAS) += $(CXL_CORE_SRC)/ras.o
cxl_core-y += config_check.o
cxl_core-y += cxl_core_test.o
cxl_core-y += cxl_core_exports.o
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 03/25] cxl: Remove ifdef blocks of CONFIG_PCIEAER_CXL from core/pci.c
2025-09-25 22:34 ` [PATCH v12 03/25] cxl: Remove ifdef blocks of CONFIG_PCIEAER_CXL from core/pci.c Terry Bowman
@ 2025-10-03 20:11 ` Cheatham, Benjamin
0 siblings, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:11 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
[snip]
> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
> index 1fb66132b777..9f4eb7e2feba 100644
> --- a/drivers/cxl/core/core.h
> +++ b/drivers/cxl/core/core.h
> @@ -144,8 +144,20 @@ int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c);
> int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
> struct access_coordinate *c);
>
> +#ifdef CONFIG_CXL_RAS
> int cxl_ras_init(void);
> void cxl_ras_exit(void);
> +#else
> +static inline int cxl_ras_init(void)
> +{
> + return 0;
> +}
> +
> +static inline void cxl_ras_exit(void)
> +{
> +}
> +#endif // CONFIG_CXL_RAS
Nit: Comment style is wrong for this file, should be /* CONFIG_CXL_RAS */
With that:
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 04/25] CXL/AER: Remove CONFIG_PCIEAER_CXL and replace with CONFIG_CXL_RAS
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (2 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 03/25] cxl: Remove ifdef blocks of CONFIG_PCIEAER_CXL from core/pci.c Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-25 23:17 ` Dave Jiang
` (2 more replies)
2025-09-25 22:34 ` [PATCH v12 05/25] cxl: Move CXL driver RCH error handling into CONFIG_CXL_RCH_RAS conditional block Terry Bowman
` (20 subsequent siblings)
24 siblings, 3 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
CXL RAS compilation is enabled using CONFIG_CXL_RAS while the AER CXL logic
uses CONFIG_PCIEAER_CXL. The 2 share the same dependencies and can be
combined. The 2 kernel configs are unnecessary and are problematic for the
user because of the duplication. Replace occurrences of CONFIG_PCIEAER_CXL
to be CONFIG_CXL_RAS.
Update the CONFIG_CXL_RAS Kconfig definition to include dependencies 'PCIEAER
&& CXL_PCI' taken from the CONFIG_PCIEAER_CXL definition.
Remove the Kconfig CONFIG_PCIEAER_CXL definition.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
Changes in v11 -> v12:
- Added review-by for Sathyanarayanan
- Changed Kconfig dependency from PCIEAER_CXL to PCIEAER. Moved
this backwards into this patch.
Changes in v10 -> v11:
- New patch
---
drivers/cxl/Kconfig | 2 +-
drivers/pci/pcie/Kconfig | 9 ---------
drivers/pci/pcie/aer.c | 2 +-
3 files changed, 2 insertions(+), 11 deletions(-)
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 9246f734e6ca..b92d544cfe6f 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -235,5 +235,5 @@ config CXL_MCE
config CXL_RAS
def_bool y
- depends on ACPI_APEI_GHES && PCIEAER_CXL && CXL_PCI
+ depends on ACPI_APEI_GHES && PCIEAER && CXL_PCI
endif
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 17919b99fa66..207c2deae35f 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -49,15 +49,6 @@ config PCIEAER_INJECT
gotten from:
https://github.com/intel/aer-inject.git
-config PCIEAER_CXL
- bool "PCI Express CXL RAS support"
- default y
- depends on PCIEAER && CXL_PCI
- help
- Enables CXL error handling.
-
- If unsure, say Y.
-
#
# PCI Express ECRC
#
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index e286c197d716..7a1dc2a3460b 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -1087,7 +1087,7 @@ static bool find_source_device(struct pci_dev *parent,
return true;
}
-#ifdef CONFIG_PCIEAER_CXL
+#ifdef CONFIG_CXL_RAS
/**
* pci_aer_unmask_internal_errors - unmask internal errors
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 04/25] CXL/AER: Remove CONFIG_PCIEAER_CXL and replace with CONFIG_CXL_RAS
2025-09-25 22:34 ` [PATCH v12 04/25] CXL/AER: Remove CONFIG_PCIEAER_CXL and replace with CONFIG_CXL_RAS Terry Bowman
@ 2025-09-25 23:17 ` Dave Jiang
2025-10-01 15:11 ` Jonathan Cameron
2025-10-03 20:11 ` Cheatham, Benjamin
2 siblings, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-25 23:17 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> CXL RAS compilation is enabled using CONFIG_CXL_RAS while the AER CXL logic
> uses CONFIG_PCIEAER_CXL. The 2 share the same dependencies and can be
> combined. The 2 kernel configs are unnecessary and are problematic for the
> user because of the duplication. Replace occurrences of CONFIG_PCIEAER_CXL
> to be CONFIG_CXL_RAS.
>
> Update the CONFIG_CXL_RAS Kconfig definition to include dependencies 'PCIEAER
> && CXL_PCI' taken from the CONFIG_PCIEAER_CXL definition.
>
> Remove the Kconfig CONFIG_PCIEAER_CXL definition.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> ---
>
> Changes in v11 -> v12:
> - Added review-by for Sathyanarayanan
> - Changed Kconfig dependency from PCIEAER_CXL to PCIEAER. Moved
> this backwards into this patch.
>
> Changes in v10 -> v11:
> - New patch
> ---
> drivers/cxl/Kconfig | 2 +-
> drivers/pci/pcie/Kconfig | 9 ---------
> drivers/pci/pcie/aer.c | 2 +-
> 3 files changed, 2 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
> index 9246f734e6ca..b92d544cfe6f 100644
> --- a/drivers/cxl/Kconfig
> +++ b/drivers/cxl/Kconfig
> @@ -235,5 +235,5 @@ config CXL_MCE
>
> config CXL_RAS
> def_bool y
> - depends on ACPI_APEI_GHES && PCIEAER_CXL && CXL_PCI
> + depends on ACPI_APEI_GHES && PCIEAER && CXL_PCI
> endif
> diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
> index 17919b99fa66..207c2deae35f 100644
> --- a/drivers/pci/pcie/Kconfig
> +++ b/drivers/pci/pcie/Kconfig
> @@ -49,15 +49,6 @@ config PCIEAER_INJECT
> gotten from:
> https://github.com/intel/aer-inject.git
>
> -config PCIEAER_CXL
> - bool "PCI Express CXL RAS support"
> - default y
> - depends on PCIEAER && CXL_PCI
> - help
> - Enables CXL error handling.
> -
> - If unsure, say Y.
> -
> #
> # PCI Express ECRC
> #
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index e286c197d716..7a1dc2a3460b 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -1087,7 +1087,7 @@ static bool find_source_device(struct pci_dev *parent,
> return true;
> }
>
> -#ifdef CONFIG_PCIEAER_CXL
> +#ifdef CONFIG_CXL_RAS
>
> /**
> * pci_aer_unmask_internal_errors - unmask internal errors
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 04/25] CXL/AER: Remove CONFIG_PCIEAER_CXL and replace with CONFIG_CXL_RAS
2025-09-25 22:34 ` [PATCH v12 04/25] CXL/AER: Remove CONFIG_PCIEAER_CXL and replace with CONFIG_CXL_RAS Terry Bowman
2025-09-25 23:17 ` Dave Jiang
@ 2025-10-01 15:11 ` Jonathan Cameron
2025-10-03 20:11 ` Cheatham, Benjamin
2 siblings, 0 replies; 92+ messages in thread
From: Jonathan Cameron @ 2025-10-01 15:11 UTC (permalink / raw)
To: Terry Bowman
Cc: dave, dave.jiang, alison.schofield, dan.j.williams, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, linux-cxl,
alucerop, ira.weiny, linux-kernel, linux-pci
On Thu, 25 Sep 2025 17:34:19 -0500
Terry Bowman <terry.bowman@amd.com> wrote:
> CXL RAS compilation is enabled using CONFIG_CXL_RAS while the AER CXL logic
> uses CONFIG_PCIEAER_CXL. The 2 share the same dependencies and can be
> combined. The 2 kernel configs are unnecessary and are problematic for the
> user because of the duplication. Replace occurrences of CONFIG_PCIEAER_CXL
> to be CONFIG_CXL_RAS.
>
> Update the CONFIG_CXL_RAS Kconfig definition to include dependencies 'PCIEAER
> && CXL_PCI' taken from the CONFIG_PCIEAER_CXL definition.
>
> Remove the Kconfig CONFIG_PCIEAER_CXL definition.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
Seems reasonable.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 04/25] CXL/AER: Remove CONFIG_PCIEAER_CXL and replace with CONFIG_CXL_RAS
2025-09-25 22:34 ` [PATCH v12 04/25] CXL/AER: Remove CONFIG_PCIEAER_CXL and replace with CONFIG_CXL_RAS Terry Bowman
2025-09-25 23:17 ` Dave Jiang
2025-10-01 15:11 ` Jonathan Cameron
@ 2025-10-03 20:11 ` Cheatham, Benjamin
2 siblings, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:11 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-pci, dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> CXL RAS compilation is enabled using CONFIG_CXL_RAS while the AER CXL logic
> uses CONFIG_PCIEAER_CXL. The 2 share the same dependencies and can be
> combined. The 2 kernel configs are unnecessary and are problematic for the
> user because of the duplication. Replace occurrences of CONFIG_PCIEAER_CXL
> to be CONFIG_CXL_RAS.
>
> Update the CONFIG_CXL_RAS Kconfig definition to include dependencies 'PCIEAER
> && CXL_PCI' taken from the CONFIG_PCIEAER_CXL definition.
>
> Remove the Kconfig CONFIG_PCIEAER_CXL definition.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> ---
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 05/25] cxl: Move CXL driver RCH error handling into CONFIG_CXL_RCH_RAS conditional block
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (3 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 04/25] CXL/AER: Remove CONFIG_PCIEAER_CXL and replace with CONFIG_CXL_RAS Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-25 23:31 ` Dave Jiang
2025-10-03 20:11 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors Terry Bowman
` (19 subsequent siblings)
24 siblings, 2 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
Restricted CXL Host (RCH) protocol error handling uses a procedure distinct
from the CXL Virtual Hierarchy (VH) handling. This is because of the
differences in the RCH and VH topologies. Improve the maintainability and
add ability to enable/disable RCH handling.
Move and combine the RCH handling code into a single block conditionally
compiled with the CONFIG_CXL_RCH_RAS kernel config.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
v11->v12:
- Moved CXL_RCH_RAS Kconfig definition here from following commit.
v10->v11:
- New patch
---
drivers/cxl/Kconfig | 7 ++
drivers/cxl/core/ras.c | 178 +++++++++++++++++++++--------------------
2 files changed, 100 insertions(+), 85 deletions(-)
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index b92d544cfe6f..028201e24523 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -236,4 +236,11 @@ config CXL_MCE
config CXL_RAS
def_bool y
depends on ACPI_APEI_GHES && PCIEAER && CXL_PCI
+
+config CXL_RCH_RAS
+ bool "CXL: Restricted CXL Host (RCH) protocol error handling"
+ def_bool n
+ depends on CXL_RAS
+ help
+ RAS support for Restricted CXL Host (RCH) defined in CXL1.1.
endif
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 0875ce8116ff..1ec4ea8c56f1 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -126,6 +126,10 @@ void cxl_ras_exit(void)
cancel_work_sync(&cxl_cper_prot_err_work);
}
+static void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
+static bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
+
+#ifdef CONFIG_CXL_RCH_RAS
static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
{
resource_size_t aer_phys;
@@ -141,18 +145,6 @@ static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
}
}
-static void cxl_dport_map_ras(struct cxl_dport *dport)
-{
- struct cxl_register_map *map = &dport->reg_map;
- struct device *dev = dport->dport_dev;
-
- if (!map->component_map.ras.valid)
- dev_dbg(dev, "RAS registers not found\n");
- else if (cxl_map_component_regs(map, &dport->regs.component,
- BIT(CXL_CM_CAP_CAP_ID_RAS)))
- dev_dbg(dev, "Failed to map RAS capability.\n");
-}
-
static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
{
void __iomem *aer_base = dport->regs.dport_aer;
@@ -177,6 +169,95 @@ static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
}
+/*
+ * Copy the AER capability registers using 32 bit read accesses.
+ * This is necessary because RCRB AER capability is MMIO mapped. Clear the
+ * status after copying.
+ *
+ * @aer_base: base address of AER capability block in RCRB
+ * @aer_regs: destination for copying AER capability
+ */
+static bool cxl_rch_get_aer_info(void __iomem *aer_base,
+ struct aer_capability_regs *aer_regs)
+{
+ int read_cnt = sizeof(struct aer_capability_regs) / sizeof(u32);
+ u32 *aer_regs_buf = (u32 *)aer_regs;
+ int n;
+
+ if (!aer_base)
+ return false;
+
+ /* Use readl() to guarantee 32-bit accesses */
+ for (n = 0; n < read_cnt; n++)
+ aer_regs_buf[n] = readl(aer_base + n * sizeof(u32));
+
+ writel(aer_regs->uncor_status, aer_base + PCI_ERR_UNCOR_STATUS);
+ writel(aer_regs->cor_status, aer_base + PCI_ERR_COR_STATUS);
+
+ return true;
+}
+
+/* Get AER severity. Return false if there is no error. */
+static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,
+ int *severity)
+{
+ if (aer_regs->uncor_status & ~aer_regs->uncor_mask) {
+ if (aer_regs->uncor_status & PCI_ERR_ROOT_FATAL_RCV)
+ *severity = AER_FATAL;
+ else
+ *severity = AER_NONFATAL;
+ return true;
+ }
+
+ if (aer_regs->cor_status & ~aer_regs->cor_mask) {
+ *severity = AER_CORRECTABLE;
+ return true;
+ }
+
+ return false;
+}
+
+static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
+{
+ struct pci_dev *pdev = to_pci_dev(cxlds->dev);
+ struct aer_capability_regs aer_regs;
+ struct cxl_dport *dport;
+ int severity;
+
+ struct cxl_port *port __free(put_cxl_port) =
+ cxl_pci_find_port(pdev, &dport);
+ if (!port)
+ return;
+
+ if (!cxl_rch_get_aer_info(dport->regs.dport_aer, &aer_regs))
+ return;
+
+ if (!cxl_rch_get_aer_severity(&aer_regs, &severity))
+ return;
+
+ pci_print_aer(pdev, severity, &aer_regs);
+ if (severity == AER_CORRECTABLE)
+ cxl_handle_cor_ras(cxlds, dport->regs.ras);
+ else
+ cxl_handle_ras(cxlds, dport->regs.ras);
+}
+#else
+static inline void cxl_dport_map_rch_aer(struct cxl_dport *dport) { }
+static inline void cxl_disable_rch_root_ints(struct cxl_dport *dport) { }
+static inline void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { }
+#endif
+
+static void cxl_dport_map_ras(struct cxl_dport *dport)
+{
+ struct cxl_register_map *map = &dport->reg_map;
+ struct device *dev = dport->dport_dev;
+
+ if (!map->component_map.ras.valid)
+ dev_dbg(dev, "RAS registers not found\n");
+ else if (cxl_map_component_regs(map, &dport->regs.component,
+ BIT(CXL_CM_CAP_CAP_ID_RAS)))
+ dev_dbg(dev, "Failed to map RAS capability.\n");
+}
/**
* cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
@@ -270,79 +351,6 @@ static bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base)
return true;
}
-/*
- * Copy the AER capability registers using 32 bit read accesses.
- * This is necessary because RCRB AER capability is MMIO mapped. Clear the
- * status after copying.
- *
- * @aer_base: base address of AER capability block in RCRB
- * @aer_regs: destination for copying AER capability
- */
-static bool cxl_rch_get_aer_info(void __iomem *aer_base,
- struct aer_capability_regs *aer_regs)
-{
- int read_cnt = sizeof(struct aer_capability_regs) / sizeof(u32);
- u32 *aer_regs_buf = (u32 *)aer_regs;
- int n;
-
- if (!aer_base)
- return false;
-
- /* Use readl() to guarantee 32-bit accesses */
- for (n = 0; n < read_cnt; n++)
- aer_regs_buf[n] = readl(aer_base + n * sizeof(u32));
-
- writel(aer_regs->uncor_status, aer_base + PCI_ERR_UNCOR_STATUS);
- writel(aer_regs->cor_status, aer_base + PCI_ERR_COR_STATUS);
-
- return true;
-}
-
-/* Get AER severity. Return false if there is no error. */
-static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,
- int *severity)
-{
- if (aer_regs->uncor_status & ~aer_regs->uncor_mask) {
- if (aer_regs->uncor_status & PCI_ERR_ROOT_FATAL_RCV)
- *severity = AER_FATAL;
- else
- *severity = AER_NONFATAL;
- return true;
- }
-
- if (aer_regs->cor_status & ~aer_regs->cor_mask) {
- *severity = AER_CORRECTABLE;
- return true;
- }
-
- return false;
-}
-
-static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
-{
- struct pci_dev *pdev = to_pci_dev(cxlds->dev);
- struct aer_capability_regs aer_regs;
- struct cxl_dport *dport;
- int severity;
-
- struct cxl_port *port __free(put_cxl_port) =
- cxl_pci_find_port(pdev, &dport);
- if (!port)
- return;
-
- if (!cxl_rch_get_aer_info(dport->regs.dport_aer, &aer_regs))
- return;
-
- if (!cxl_rch_get_aer_severity(&aer_regs, &severity))
- return;
-
- pci_print_aer(pdev, severity, &aer_regs);
- if (severity == AER_CORRECTABLE)
- cxl_handle_cor_ras(cxlds, dport->regs.ras);
- else
- cxl_handle_ras(cxlds, dport->regs.ras);
-}
-
void cxl_cor_error_detected(struct pci_dev *pdev)
{
struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 05/25] cxl: Move CXL driver RCH error handling into CONFIG_CXL_RCH_RAS conditional block
2025-09-25 22:34 ` [PATCH v12 05/25] cxl: Move CXL driver RCH error handling into CONFIG_CXL_RCH_RAS conditional block Terry Bowman
@ 2025-09-25 23:31 ` Dave Jiang
2025-10-01 15:23 ` Jonathan Cameron
2025-10-03 20:11 ` Cheatham, Benjamin
1 sibling, 1 reply; 92+ messages in thread
From: Dave Jiang @ 2025-09-25 23:31 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> Restricted CXL Host (RCH) protocol error handling uses a procedure distinct
> from the CXL Virtual Hierarchy (VH) handling. This is because of the
> differences in the RCH and VH topologies. Improve the maintainability and
> add ability to enable/disable RCH handling.
>
> Move and combine the RCH handling code into a single block conditionally
> compiled with the CONFIG_CXL_RCH_RAS kernel config.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>
> ---
>
> v11->v12:
> - Moved CXL_RCH_RAS Kconfig definition here from following commit.
>
> v10->v11:
> - New patch
> ---
> drivers/cxl/Kconfig | 7 ++
> drivers/cxl/core/ras.c | 178 +++++++++++++++++++++--------------------
> 2 files changed, 100 insertions(+), 85 deletions(-)
>
> diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
> index b92d544cfe6f..028201e24523 100644
> --- a/drivers/cxl/Kconfig
> +++ b/drivers/cxl/Kconfig
> @@ -236,4 +236,11 @@ config CXL_MCE
> config CXL_RAS
> def_bool y
> depends on ACPI_APEI_GHES && PCIEAER && CXL_PCI
> +
> +config CXL_RCH_RAS
> + bool "CXL: Restricted CXL Host (RCH) protocol error handling"
> + def_bool n
> + depends on CXL_RAS
> + help
> + RAS support for Restricted CXL Host (RCH) defined in CXL1.1.
> endif
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 0875ce8116ff..1ec4ea8c56f1 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -126,6 +126,10 @@ void cxl_ras_exit(void)
> cancel_work_sync(&cxl_cper_prot_err_work);
> }
>
> +static void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
> +static bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
> +
> +#ifdef CONFIG_CXL_RCH_RAS
I don't love this in the C file. If we are going to have a Kconfig that we can use to gate the code, maybe we need core/ras_rch.c? Don't forget to add the new object entry to KBuild for cxl_test when you do that.
DJ
> static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
> {
> resource_size_t aer_phys;
> @@ -141,18 +145,6 @@ static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
> }
> }
>
> -static void cxl_dport_map_ras(struct cxl_dport *dport)
> -{
> - struct cxl_register_map *map = &dport->reg_map;
> - struct device *dev = dport->dport_dev;
> -
> - if (!map->component_map.ras.valid)
> - dev_dbg(dev, "RAS registers not found\n");
> - else if (cxl_map_component_regs(map, &dport->regs.component,
> - BIT(CXL_CM_CAP_CAP_ID_RAS)))
> - dev_dbg(dev, "Failed to map RAS capability.\n");
> -}
> -
> static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
> {
> void __iomem *aer_base = dport->regs.dport_aer;
> @@ -177,6 +169,95 @@ static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
> writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
> }
>
> +/*
> + * Copy the AER capability registers using 32 bit read accesses.
> + * This is necessary because RCRB AER capability is MMIO mapped. Clear the
> + * status after copying.
> + *
> + * @aer_base: base address of AER capability block in RCRB
> + * @aer_regs: destination for copying AER capability
> + */
> +static bool cxl_rch_get_aer_info(void __iomem *aer_base,
> + struct aer_capability_regs *aer_regs)
> +{
> + int read_cnt = sizeof(struct aer_capability_regs) / sizeof(u32);
> + u32 *aer_regs_buf = (u32 *)aer_regs;
> + int n;
> +
> + if (!aer_base)
> + return false;
> +
> + /* Use readl() to guarantee 32-bit accesses */
> + for (n = 0; n < read_cnt; n++)
> + aer_regs_buf[n] = readl(aer_base + n * sizeof(u32));
> +
> + writel(aer_regs->uncor_status, aer_base + PCI_ERR_UNCOR_STATUS);
> + writel(aer_regs->cor_status, aer_base + PCI_ERR_COR_STATUS);
> +
> + return true;
> +}
> +
> +/* Get AER severity. Return false if there is no error. */
> +static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,
> + int *severity)
> +{
> + if (aer_regs->uncor_status & ~aer_regs->uncor_mask) {
> + if (aer_regs->uncor_status & PCI_ERR_ROOT_FATAL_RCV)
> + *severity = AER_FATAL;
> + else
> + *severity = AER_NONFATAL;
> + return true;
> + }
> +
> + if (aer_regs->cor_status & ~aer_regs->cor_mask) {
> + *severity = AER_CORRECTABLE;
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
> +{
> + struct pci_dev *pdev = to_pci_dev(cxlds->dev);
> + struct aer_capability_regs aer_regs;
> + struct cxl_dport *dport;
> + int severity;
> +
> + struct cxl_port *port __free(put_cxl_port) =
> + cxl_pci_find_port(pdev, &dport);
> + if (!port)
> + return;
> +
> + if (!cxl_rch_get_aer_info(dport->regs.dport_aer, &aer_regs))
> + return;
> +
> + if (!cxl_rch_get_aer_severity(&aer_regs, &severity))
> + return;
> +
> + pci_print_aer(pdev, severity, &aer_regs);
> + if (severity == AER_CORRECTABLE)
> + cxl_handle_cor_ras(cxlds, dport->regs.ras);
> + else
> + cxl_handle_ras(cxlds, dport->regs.ras);
> +}
> +#else
> +static inline void cxl_dport_map_rch_aer(struct cxl_dport *dport) { }
> +static inline void cxl_disable_rch_root_ints(struct cxl_dport *dport) { }
> +static inline void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { }
> +#endif
> +
> +static void cxl_dport_map_ras(struct cxl_dport *dport)
> +{
> + struct cxl_register_map *map = &dport->reg_map;
> + struct device *dev = dport->dport_dev;
> +
> + if (!map->component_map.ras.valid)
> + dev_dbg(dev, "RAS registers not found\n");
> + else if (cxl_map_component_regs(map, &dport->regs.component,
> + BIT(CXL_CM_CAP_CAP_ID_RAS)))
> + dev_dbg(dev, "Failed to map RAS capability.\n");
> +}
>
> /**
> * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
> @@ -270,79 +351,6 @@ static bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base)
> return true;
> }
>
> -/*
> - * Copy the AER capability registers using 32 bit read accesses.
> - * This is necessary because RCRB AER capability is MMIO mapped. Clear the
> - * status after copying.
> - *
> - * @aer_base: base address of AER capability block in RCRB
> - * @aer_regs: destination for copying AER capability
> - */
> -static bool cxl_rch_get_aer_info(void __iomem *aer_base,
> - struct aer_capability_regs *aer_regs)
> -{
> - int read_cnt = sizeof(struct aer_capability_regs) / sizeof(u32);
> - u32 *aer_regs_buf = (u32 *)aer_regs;
> - int n;
> -
> - if (!aer_base)
> - return false;
> -
> - /* Use readl() to guarantee 32-bit accesses */
> - for (n = 0; n < read_cnt; n++)
> - aer_regs_buf[n] = readl(aer_base + n * sizeof(u32));
> -
> - writel(aer_regs->uncor_status, aer_base + PCI_ERR_UNCOR_STATUS);
> - writel(aer_regs->cor_status, aer_base + PCI_ERR_COR_STATUS);
> -
> - return true;
> -}
> -
> -/* Get AER severity. Return false if there is no error. */
> -static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,
> - int *severity)
> -{
> - if (aer_regs->uncor_status & ~aer_regs->uncor_mask) {
> - if (aer_regs->uncor_status & PCI_ERR_ROOT_FATAL_RCV)
> - *severity = AER_FATAL;
> - else
> - *severity = AER_NONFATAL;
> - return true;
> - }
> -
> - if (aer_regs->cor_status & ~aer_regs->cor_mask) {
> - *severity = AER_CORRECTABLE;
> - return true;
> - }
> -
> - return false;
> -}
> -
> -static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
> -{
> - struct pci_dev *pdev = to_pci_dev(cxlds->dev);
> - struct aer_capability_regs aer_regs;
> - struct cxl_dport *dport;
> - int severity;
> -
> - struct cxl_port *port __free(put_cxl_port) =
> - cxl_pci_find_port(pdev, &dport);
> - if (!port)
> - return;
> -
> - if (!cxl_rch_get_aer_info(dport->regs.dport_aer, &aer_regs))
> - return;
> -
> - if (!cxl_rch_get_aer_severity(&aer_regs, &severity))
> - return;
> -
> - pci_print_aer(pdev, severity, &aer_regs);
> - if (severity == AER_CORRECTABLE)
> - cxl_handle_cor_ras(cxlds, dport->regs.ras);
> - else
> - cxl_handle_ras(cxlds, dport->regs.ras);
> -}
> -
> void cxl_cor_error_detected(struct pci_dev *pdev)
> {
> struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 05/25] cxl: Move CXL driver RCH error handling into CONFIG_CXL_RCH_RAS conditional block
2025-09-25 23:31 ` Dave Jiang
@ 2025-10-01 15:23 ` Jonathan Cameron
0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Cameron @ 2025-10-01 15:23 UTC (permalink / raw)
To: Dave Jiang
Cc: Terry Bowman, dave, alison.schofield, dan.j.williams, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, linux-cxl,
alucerop, ira.weiny, linux-kernel, linux-pci
> > diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> > index 0875ce8116ff..1ec4ea8c56f1 100644
> > --- a/drivers/cxl/core/ras.c
> > +++ b/drivers/cxl/core/ras.c
> > @@ -126,6 +126,10 @@ void cxl_ras_exit(void)
> > cancel_work_sync(&cxl_cper_prot_err_work);
> > }
> >
> > +static void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
> > +static bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
> > +
> > +#ifdef CONFIG_CXL_RCH_RAS
>
> I don't love this in the C file. If we are going to have a Kconfig that we can use to gate the code, maybe we need core/ras_rch.c? Don't forget to add the new object entry to KBuild for cxl_test when you do that.
>
Seconded. Seems worth an extra file to me as well.
J
> DJ
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 05/25] cxl: Move CXL driver RCH error handling into CONFIG_CXL_RCH_RAS conditional block
2025-09-25 22:34 ` [PATCH v12 05/25] cxl: Move CXL driver RCH error handling into CONFIG_CXL_RCH_RAS conditional block Terry Bowman
2025-09-25 23:31 ` Dave Jiang
@ 2025-10-03 20:11 ` Cheatham, Benjamin
2025-10-06 18:52 ` Bowman, Terry
1 sibling, 1 reply; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:11 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-pci, dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
[snip]
> +
> +config CXL_RCH_RAS
> + bool "CXL: Restricted CXL Host (RCH) protocol error handling"
> + def_bool n
> + depends on CXL_RAS
> + help
> + RAS support for Restricted CXL Host (RCH) defined in CXL1.1.
Seems a little terse for a config help message. Maybe something like: "RAS support for
Restricted CXL Hosts (RCH) as defined in the CXL 1.1 specification."?
Do we also want to default to 'n' here? I realize that 1.1 devices aren't exactly popular
but 2.0+ devices/hosts are still pretty new. I haven't looked at the rest of the series yet,
but if this is the majority of the RCH support then it's small enough to include by default
imo.
I'm fine with leaving 'n' as the default but I thought I'd make the argument for including
it by default just in case.
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 05/25] cxl: Move CXL driver RCH error handling into CONFIG_CXL_RCH_RAS conditional block
2025-10-03 20:11 ` Cheatham, Benjamin
@ 2025-10-06 18:52 ` Bowman, Terry
0 siblings, 0 replies; 92+ messages in thread
From: Bowman, Terry @ 2025-10-06 18:52 UTC (permalink / raw)
To: Cheatham, Benjamin
Cc: linux-pci, dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 10/3/2025 3:11 PM, Cheatham, Benjamin wrote:
> [snip]
>
>> +
>> +config CXL_RCH_RAS
>> + bool "CXL: Restricted CXL Host (RCH) protocol error handling"
>> + def_bool n
>> + depends on CXL_RAS
>> + help
>> + RAS support for Restricted CXL Host (RCH) defined in CXL1.1.
> Seems a little terse for a config help message. Maybe something like: "RAS support for
> Restricted CXL Hosts (RCH) as defined in the CXL 1.1 specification."?
>
> Do we also want to default to 'n' here? I realize that 1.1 devices aren't exactly popular
> but 2.0+ devices/hosts are still pretty new. I haven't looked at the rest of the series yet,
> but if this is the majority of the RCH support then it's small enough to include by default
> imo.
>
> I'm fine with leaving 'n' as the default but I thought I'd make the argument for including
> it by default just in case.
Sure, the help message can be expanded. It would be good to use default 'n' if possible,
but, we can default 'y' if we see a need. I'm not aware of what degree, or if any, the RCH
is used.
Terry
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (4 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 05/25] cxl: Move CXL driver RCH error handling into CONFIG_CXL_RCH_RAS conditional block Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-25 23:36 ` Dave Jiang
` (3 more replies)
2025-09-25 22:34 ` [PATCH v12 07/25] CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h Terry Bowman
` (18 subsequent siblings)
24 siblings, 4 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
The restricted CXL Host (RCH) AER error handling logic currently resides
in the AER driver file, drivers/pci/pcie/aer.c. CXL specific changes are
conditionally compiled using #ifdefs.
Improve the AER driver maintainability by separating the RCH specific logic
from the AER driver's core functionality and removing the ifdefs. Introduce
drivers/pci/pcie/aer_cxl_rch.c for moving the RCH AER logic into.
Conditionally compile the file using the CONFIG_CXL_RCH_RAS Kconfig.
Move the CXL logic into the new file but leave helper functions in aer.c
for now as they will be moved in future patch for CXL virtual hierarchy
handling. Export the handler functions as needed. Export
pci_aer_unmask_internal_errors() allowing for all subsystems to use.
Avoid multiple declaration moves and export cxl_error_is_native() now to
allow for cxl_core access.
Inorder to maintain compilation after the move other changes are required.
Change cxl_rch_handle_error() & cxl_rch_enable_rcec() to be non-static
inorder for accessing from the AER driver in aer.c.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
Changes in v11->v12:
- Rename drivers/pci/pcie/cxl_rch.c to drivers/pci/pcie/aer_cxl_rch.c (Lukas)
- Removed forward declararation of 'struct aer_err_info' in pci/pci.h (Terry)
Changes in v10->v11:
- Remove changes in code-split and move to earlier, new patch
- Add #include <linux/bitfield.h> to cxl_ras.c
- Move cxl_rch_handle_error() & cxl_rch_enable_rcec() declarations from pci.h
to aer.h, more localized.
- Introduce CONFIG_CXL_RCH_RAS, includes Makefile changes, ras.c
ifdef changes
---
drivers/pci/pci.h | 14 +++++
drivers/pci/pcie/Makefile | 1 +
drivers/pci/pcie/aer.c | 108 +++------------------------------
drivers/pci/pcie/aer_cxl_rch.c | 99 ++++++++++++++++++++++++++++++
include/linux/aer.h | 8 +++
5 files changed, 129 insertions(+), 101 deletions(-)
create mode 100644 drivers/pci/pcie/aer_cxl_rch.c
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 34f65d69662e..0c7178d0ef9d 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1201,4 +1201,18 @@ static inline int pci_msix_write_tph_tag(struct pci_dev *pdev, unsigned int inde
(PCI_CONF1_ADDRESS(bus, dev, func, reg) | \
PCI_CONF1_EXT_REG(reg))
+#ifdef CONFIG_CXL_RCH_RAS
+void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info);
+void cxl_rch_enable_rcec(struct pci_dev *rcec);
+#else
+static inline void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info) { }
+static inline void cxl_rch_enable_rcec(struct pci_dev *rcec) { }
+#endif
+
+#ifdef CONFIG_CXL_RAS
+bool is_internal_error(struct aer_err_info *info);
+#else
+static inline bool is_internal_error(struct aer_err_info *info) { return false; }
+#endif
+
#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
index 173829aa02e6..970e7cbc5b34 100644
--- a/drivers/pci/pcie/Makefile
+++ b/drivers/pci/pcie/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o bwctrl.o
obj-y += aspm.o
obj-$(CONFIG_PCIEAER) += aer.o err.o tlp.o
+obj-$(CONFIG_CXL_RCH_RAS) += aer_cxl_rch.o
obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o
obj-$(CONFIG_PCIE_PME) += pme.o
obj-$(CONFIG_PCIE_DPC) += dpc.o
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 7a1dc2a3460b..6e5c9efe2920 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -1099,7 +1099,7 @@ static bool find_source_device(struct pci_dev *parent,
* Note: AER must be enabled and supported by the device which must be
* checked in advance, e.g. with pcie_aer_is_native().
*/
-static void pci_aer_unmask_internal_errors(struct pci_dev *dev)
+void pci_aer_unmask_internal_errors(struct pci_dev *dev)
{
int aer = dev->aer_cap;
u32 mask;
@@ -1112,119 +1112,25 @@ static void pci_aer_unmask_internal_errors(struct pci_dev *dev)
mask &= ~PCI_ERR_COR_INTERNAL;
pci_write_config_dword(dev, aer + PCI_ERR_COR_MASK, mask);
}
+EXPORT_SYMBOL_GPL(pci_aer_unmask_internal_errors);
-static bool is_cxl_mem_dev(struct pci_dev *dev)
-{
- /*
- * The capability, status, and control fields in Device 0,
- * Function 0 DVSEC control the CXL functionality of the
- * entire device (CXL 3.0, 8.1.3).
- */
- if (dev->devfn != PCI_DEVFN(0, 0))
- return false;
-
- /*
- * CXL Memory Devices must have the 502h class code set (CXL
- * 3.0, 8.1.12.1).
- */
- if ((dev->class >> 8) != PCI_CLASS_MEMORY_CXL)
- return false;
-
- return true;
-}
-
-static bool cxl_error_is_native(struct pci_dev *dev)
+bool cxl_error_is_native(struct pci_dev *dev)
{
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
return (pcie_ports_native || host->native_aer);
}
+EXPORT_SYMBOL_NS_GPL(cxl_error_is_native, "CXL");
-static bool is_internal_error(struct aer_err_info *info)
+bool is_internal_error(struct aer_err_info *info)
{
if (info->severity == AER_CORRECTABLE)
return info->status & PCI_ERR_COR_INTERNAL;
return info->status & PCI_ERR_UNC_INTN;
}
-
-static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
-{
- struct aer_err_info *info = (struct aer_err_info *)data;
- const struct pci_error_handlers *err_handler;
-
- if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
- return 0;
-
- /* Protect dev->driver */
- device_lock(&dev->dev);
-
- err_handler = dev->driver ? dev->driver->err_handler : NULL;
- if (!err_handler)
- goto out;
-
- if (info->severity == AER_CORRECTABLE) {
- if (err_handler->cor_error_detected)
- err_handler->cor_error_detected(dev);
- } else if (err_handler->error_detected) {
- if (info->severity == AER_NONFATAL)
- err_handler->error_detected(dev, pci_channel_io_normal);
- else if (info->severity == AER_FATAL)
- err_handler->error_detected(dev, pci_channel_io_frozen);
- }
-out:
- device_unlock(&dev->dev);
- return 0;
-}
-
-static void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info)
-{
- /*
- * Internal errors of an RCEC indicate an AER error in an
- * RCH's downstream port. Check and handle them in the CXL.mem
- * device driver.
- */
- if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC &&
- is_internal_error(info))
- pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
-}
-
-static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
-{
- bool *handles_cxl = data;
-
- if (!*handles_cxl)
- *handles_cxl = is_cxl_mem_dev(dev) && cxl_error_is_native(dev);
-
- /* Non-zero terminates iteration */
- return *handles_cxl;
-}
-
-static bool handles_cxl_errors(struct pci_dev *rcec)
-{
- bool handles_cxl = false;
-
- if (pci_pcie_type(rcec) == PCI_EXP_TYPE_RC_EC &&
- pcie_aer_is_native(rcec))
- pcie_walk_rcec(rcec, handles_cxl_error_iter, &handles_cxl);
-
- return handles_cxl;
-}
-
-static void cxl_rch_enable_rcec(struct pci_dev *rcec)
-{
- if (!handles_cxl_errors(rcec))
- return;
-
- pci_aer_unmask_internal_errors(rcec);
- pci_info(rcec, "CXL: Internal errors unmasked");
-}
-
-#else
-static inline void cxl_rch_enable_rcec(struct pci_dev *dev) { }
-static inline void cxl_rch_handle_error(struct pci_dev *dev,
- struct aer_err_info *info) { }
-#endif
+EXPORT_SYMBOL_NS_GPL(is_internal_error, "CXL");
+#endif /* CONFIG_CXL_RAS */
/**
* pci_aer_handle_error - handle logging error into an event log
diff --git a/drivers/pci/pcie/aer_cxl_rch.c b/drivers/pci/pcie/aer_cxl_rch.c
new file mode 100644
index 000000000000..bfe071eebf67
--- /dev/null
+++ b/drivers/pci/pcie/aer_cxl_rch.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2025 AMD Corporation. All rights reserved. */
+
+#include <linux/pci.h>
+#include <linux/aer.h>
+#include <linux/bitfield.h>
+#include "../pci.h"
+
+static bool is_cxl_mem_dev(struct pci_dev *dev)
+{
+ /*
+ * The capability, status, and control fields in Device 0,
+ * Function 0 DVSEC control the CXL functionality of the
+ * entire device (CXL 3.0, 8.1.3).
+ */
+ if (dev->devfn != PCI_DEVFN(0, 0))
+ return false;
+
+ /*
+ * CXL Memory Devices must have the 502h class code set (CXL
+ * 3.0, 8.1.12.1).
+ */
+ if ((dev->class >> 8) != PCI_CLASS_MEMORY_CXL)
+ return false;
+
+ return true;
+}
+
+static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
+{
+ struct aer_err_info *info = (struct aer_err_info *)data;
+ const struct pci_error_handlers *err_handler;
+
+ if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
+ return 0;
+
+ /* Protect dev->driver */
+ device_lock(&dev->dev);
+
+ err_handler = dev->driver ? dev->driver->err_handler : NULL;
+ if (!err_handler)
+ goto out;
+
+ if (info->severity == AER_CORRECTABLE) {
+ if (err_handler->cor_error_detected)
+ err_handler->cor_error_detected(dev);
+ } else if (err_handler->error_detected) {
+ if (info->severity == AER_NONFATAL)
+ err_handler->error_detected(dev, pci_channel_io_normal);
+ else if (info->severity == AER_FATAL)
+ err_handler->error_detected(dev, pci_channel_io_frozen);
+ }
+out:
+ device_unlock(&dev->dev);
+ return 0;
+}
+
+void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info)
+{
+ /*
+ * Internal errors of an RCEC indicate an AER error in an
+ * RCH's downstream port. Check and handle them in the CXL.mem
+ * device driver.
+ */
+ if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC &&
+ is_internal_error(info))
+ pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
+}
+
+static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
+{
+ bool *handles_cxl = data;
+
+ if (!*handles_cxl)
+ *handles_cxl = is_cxl_mem_dev(dev) && cxl_error_is_native(dev);
+
+ /* Non-zero terminates iteration */
+ return *handles_cxl;
+}
+
+static bool handles_cxl_errors(struct pci_dev *rcec)
+{
+ bool handles_cxl = false;
+
+ if (pci_pcie_type(rcec) == PCI_EXP_TYPE_RC_EC &&
+ pcie_aer_is_native(rcec))
+ pcie_walk_rcec(rcec, handles_cxl_error_iter, &handles_cxl);
+
+ return handles_cxl;
+}
+
+void cxl_rch_enable_rcec(struct pci_dev *rcec)
+{
+ if (!handles_cxl_errors(rcec))
+ return;
+
+ pci_aer_unmask_internal_errors(rcec);
+ pci_info(rcec, "CXL: Internal errors unmasked");
+}
diff --git a/include/linux/aer.h b/include/linux/aer.h
index 02940be66324..2ef820563996 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -56,12 +56,20 @@ struct aer_capability_regs {
#if defined(CONFIG_PCIEAER)
int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
int pcie_aer_is_native(struct pci_dev *dev);
+void pci_aer_unmask_internal_errors(struct pci_dev *dev);
#else
static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
{
return -EINVAL;
}
static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
+static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
+#endif
+
+#ifdef CONFIG_CXL_RAS
+bool cxl_error_is_native(struct pci_dev *dev);
+#else
+static inline bool cxl_error_is_native(struct pci_dev *dev) { return false; }
#endif
void pci_print_aer(struct pci_dev *dev, int aer_severity,
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors
2025-09-25 22:34 ` [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors Terry Bowman
@ 2025-09-25 23:36 ` Dave Jiang
2025-09-26 12:32 ` kernel test robot
` (2 subsequent siblings)
3 siblings, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-25 23:36 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> The restricted CXL Host (RCH) AER error handling logic currently resides
> in the AER driver file, drivers/pci/pcie/aer.c. CXL specific changes are
> conditionally compiled using #ifdefs.
>
> Improve the AER driver maintainability by separating the RCH specific logic
> from the AER driver's core functionality and removing the ifdefs. Introduce
> drivers/pci/pcie/aer_cxl_rch.c for moving the RCH AER logic into.
> Conditionally compile the file using the CONFIG_CXL_RCH_RAS Kconfig.
>
> Move the CXL logic into the new file but leave helper functions in aer.c
> for now as they will be moved in future patch for CXL virtual hierarchy
> handling. Export the handler functions as needed. Export
> pci_aer_unmask_internal_errors() allowing for all subsystems to use.
> Avoid multiple declaration moves and export cxl_error_is_native() now to
> allow for cxl_core access.
>
> Inorder to maintain compilation after the move other changes are required.
> Change cxl_rch_handle_error() & cxl_rch_enable_rcec() to be non-static
> inorder for accessing from the AER driver in aer.c.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Seems straight forward enough
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> ---
>
> Changes in v11->v12:
> - Rename drivers/pci/pcie/cxl_rch.c to drivers/pci/pcie/aer_cxl_rch.c (Lukas)
> - Removed forward declararation of 'struct aer_err_info' in pci/pci.h (Terry)
>
> Changes in v10->v11:
> - Remove changes in code-split and move to earlier, new patch
> - Add #include <linux/bitfield.h> to cxl_ras.c
> - Move cxl_rch_handle_error() & cxl_rch_enable_rcec() declarations from pci.h
> to aer.h, more localized.
> - Introduce CONFIG_CXL_RCH_RAS, includes Makefile changes, ras.c
> ifdef changes
> ---
> drivers/pci/pci.h | 14 +++++
> drivers/pci/pcie/Makefile | 1 +
> drivers/pci/pcie/aer.c | 108 +++------------------------------
> drivers/pci/pcie/aer_cxl_rch.c | 99 ++++++++++++++++++++++++++++++
> include/linux/aer.h | 8 +++
> 5 files changed, 129 insertions(+), 101 deletions(-)
> create mode 100644 drivers/pci/pcie/aer_cxl_rch.c
>
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 34f65d69662e..0c7178d0ef9d 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -1201,4 +1201,18 @@ static inline int pci_msix_write_tph_tag(struct pci_dev *pdev, unsigned int inde
> (PCI_CONF1_ADDRESS(bus, dev, func, reg) | \
> PCI_CONF1_EXT_REG(reg))
>
> +#ifdef CONFIG_CXL_RCH_RAS
> +void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info);
> +void cxl_rch_enable_rcec(struct pci_dev *rcec);
> +#else
> +static inline void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info) { }
> +static inline void cxl_rch_enable_rcec(struct pci_dev *rcec) { }
> +#endif
> +
> +#ifdef CONFIG_CXL_RAS
> +bool is_internal_error(struct aer_err_info *info);
> +#else
> +static inline bool is_internal_error(struct aer_err_info *info) { return false; }
> +#endif
> +
> #endif /* DRIVERS_PCI_H */
> diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
> index 173829aa02e6..970e7cbc5b34 100644
> --- a/drivers/pci/pcie/Makefile
> +++ b/drivers/pci/pcie/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o bwctrl.o
>
> obj-y += aspm.o
> obj-$(CONFIG_PCIEAER) += aer.o err.o tlp.o
> +obj-$(CONFIG_CXL_RCH_RAS) += aer_cxl_rch.o
> obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o
> obj-$(CONFIG_PCIE_PME) += pme.o
> obj-$(CONFIG_PCIE_DPC) += dpc.o
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index 7a1dc2a3460b..6e5c9efe2920 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -1099,7 +1099,7 @@ static bool find_source_device(struct pci_dev *parent,
> * Note: AER must be enabled and supported by the device which must be
> * checked in advance, e.g. with pcie_aer_is_native().
> */
> -static void pci_aer_unmask_internal_errors(struct pci_dev *dev)
> +void pci_aer_unmask_internal_errors(struct pci_dev *dev)
> {
> int aer = dev->aer_cap;
> u32 mask;
> @@ -1112,119 +1112,25 @@ static void pci_aer_unmask_internal_errors(struct pci_dev *dev)
> mask &= ~PCI_ERR_COR_INTERNAL;
> pci_write_config_dword(dev, aer + PCI_ERR_COR_MASK, mask);
> }
> +EXPORT_SYMBOL_GPL(pci_aer_unmask_internal_errors);
>
> -static bool is_cxl_mem_dev(struct pci_dev *dev)
> -{
> - /*
> - * The capability, status, and control fields in Device 0,
> - * Function 0 DVSEC control the CXL functionality of the
> - * entire device (CXL 3.0, 8.1.3).
> - */
> - if (dev->devfn != PCI_DEVFN(0, 0))
> - return false;
> -
> - /*
> - * CXL Memory Devices must have the 502h class code set (CXL
> - * 3.0, 8.1.12.1).
> - */
> - if ((dev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> - return false;
> -
> - return true;
> -}
> -
> -static bool cxl_error_is_native(struct pci_dev *dev)
> +bool cxl_error_is_native(struct pci_dev *dev)
> {
> struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
>
> return (pcie_ports_native || host->native_aer);
> }
> +EXPORT_SYMBOL_NS_GPL(cxl_error_is_native, "CXL");
>
> -static bool is_internal_error(struct aer_err_info *info)
> +bool is_internal_error(struct aer_err_info *info)
> {
> if (info->severity == AER_CORRECTABLE)
> return info->status & PCI_ERR_COR_INTERNAL;
>
> return info->status & PCI_ERR_UNC_INTN;
> }
> -
> -static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
> -{
> - struct aer_err_info *info = (struct aer_err_info *)data;
> - const struct pci_error_handlers *err_handler;
> -
> - if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
> - return 0;
> -
> - /* Protect dev->driver */
> - device_lock(&dev->dev);
> -
> - err_handler = dev->driver ? dev->driver->err_handler : NULL;
> - if (!err_handler)
> - goto out;
> -
> - if (info->severity == AER_CORRECTABLE) {
> - if (err_handler->cor_error_detected)
> - err_handler->cor_error_detected(dev);
> - } else if (err_handler->error_detected) {
> - if (info->severity == AER_NONFATAL)
> - err_handler->error_detected(dev, pci_channel_io_normal);
> - else if (info->severity == AER_FATAL)
> - err_handler->error_detected(dev, pci_channel_io_frozen);
> - }
> -out:
> - device_unlock(&dev->dev);
> - return 0;
> -}
> -
> -static void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info)
> -{
> - /*
> - * Internal errors of an RCEC indicate an AER error in an
> - * RCH's downstream port. Check and handle them in the CXL.mem
> - * device driver.
> - */
> - if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC &&
> - is_internal_error(info))
> - pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
> -}
> -
> -static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
> -{
> - bool *handles_cxl = data;
> -
> - if (!*handles_cxl)
> - *handles_cxl = is_cxl_mem_dev(dev) && cxl_error_is_native(dev);
> -
> - /* Non-zero terminates iteration */
> - return *handles_cxl;
> -}
> -
> -static bool handles_cxl_errors(struct pci_dev *rcec)
> -{
> - bool handles_cxl = false;
> -
> - if (pci_pcie_type(rcec) == PCI_EXP_TYPE_RC_EC &&
> - pcie_aer_is_native(rcec))
> - pcie_walk_rcec(rcec, handles_cxl_error_iter, &handles_cxl);
> -
> - return handles_cxl;
> -}
> -
> -static void cxl_rch_enable_rcec(struct pci_dev *rcec)
> -{
> - if (!handles_cxl_errors(rcec))
> - return;
> -
> - pci_aer_unmask_internal_errors(rcec);
> - pci_info(rcec, "CXL: Internal errors unmasked");
> -}
> -
> -#else
> -static inline void cxl_rch_enable_rcec(struct pci_dev *dev) { }
> -static inline void cxl_rch_handle_error(struct pci_dev *dev,
> - struct aer_err_info *info) { }
> -#endif
> +EXPORT_SYMBOL_NS_GPL(is_internal_error, "CXL");
> +#endif /* CONFIG_CXL_RAS */
>
> /**
> * pci_aer_handle_error - handle logging error into an event log
> diff --git a/drivers/pci/pcie/aer_cxl_rch.c b/drivers/pci/pcie/aer_cxl_rch.c
> new file mode 100644
> index 000000000000..bfe071eebf67
> --- /dev/null
> +++ b/drivers/pci/pcie/aer_cxl_rch.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright(c) 2025 AMD Corporation. All rights reserved. */
> +
> +#include <linux/pci.h>
> +#include <linux/aer.h>
> +#include <linux/bitfield.h>
> +#include "../pci.h"
> +
> +static bool is_cxl_mem_dev(struct pci_dev *dev)
> +{
> + /*
> + * The capability, status, and control fields in Device 0,
> + * Function 0 DVSEC control the CXL functionality of the
> + * entire device (CXL 3.0, 8.1.3).
> + */
> + if (dev->devfn != PCI_DEVFN(0, 0))
> + return false;
> +
> + /*
> + * CXL Memory Devices must have the 502h class code set (CXL
> + * 3.0, 8.1.12.1).
> + */
> + if ((dev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> + return false;
> +
> + return true;
> +}
> +
> +static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
> +{
> + struct aer_err_info *info = (struct aer_err_info *)data;
> + const struct pci_error_handlers *err_handler;
> +
> + if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
> + return 0;
> +
> + /* Protect dev->driver */
> + device_lock(&dev->dev);
> +
> + err_handler = dev->driver ? dev->driver->err_handler : NULL;
> + if (!err_handler)
> + goto out;
> +
> + if (info->severity == AER_CORRECTABLE) {
> + if (err_handler->cor_error_detected)
> + err_handler->cor_error_detected(dev);
> + } else if (err_handler->error_detected) {
> + if (info->severity == AER_NONFATAL)
> + err_handler->error_detected(dev, pci_channel_io_normal);
> + else if (info->severity == AER_FATAL)
> + err_handler->error_detected(dev, pci_channel_io_frozen);
> + }
> +out:
> + device_unlock(&dev->dev);
> + return 0;
> +}
> +
> +void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info)
> +{
> + /*
> + * Internal errors of an RCEC indicate an AER error in an
> + * RCH's downstream port. Check and handle them in the CXL.mem
> + * device driver.
> + */
> + if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC &&
> + is_internal_error(info))
> + pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
> +}
> +
> +static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
> +{
> + bool *handles_cxl = data;
> +
> + if (!*handles_cxl)
> + *handles_cxl = is_cxl_mem_dev(dev) && cxl_error_is_native(dev);
> +
> + /* Non-zero terminates iteration */
> + return *handles_cxl;
> +}
> +
> +static bool handles_cxl_errors(struct pci_dev *rcec)
> +{
> + bool handles_cxl = false;
> +
> + if (pci_pcie_type(rcec) == PCI_EXP_TYPE_RC_EC &&
> + pcie_aer_is_native(rcec))
> + pcie_walk_rcec(rcec, handles_cxl_error_iter, &handles_cxl);
> +
> + return handles_cxl;
> +}
> +
> +void cxl_rch_enable_rcec(struct pci_dev *rcec)
> +{
> + if (!handles_cxl_errors(rcec))
> + return;
> +
> + pci_aer_unmask_internal_errors(rcec);
> + pci_info(rcec, "CXL: Internal errors unmasked");
> +}
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index 02940be66324..2ef820563996 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -56,12 +56,20 @@ struct aer_capability_regs {
> #if defined(CONFIG_PCIEAER)
> int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
> int pcie_aer_is_native(struct pci_dev *dev);
> +void pci_aer_unmask_internal_errors(struct pci_dev *dev);
> #else
> static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
> {
> return -EINVAL;
> }
> static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
> +static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
> +#endif
> +
> +#ifdef CONFIG_CXL_RAS
> +bool cxl_error_is_native(struct pci_dev *dev);
> +#else
> +static inline bool cxl_error_is_native(struct pci_dev *dev) { return false; }
> #endif
>
> void pci_print_aer(struct pci_dev *dev, int aer_severity,
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors
2025-09-25 22:34 ` [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors Terry Bowman
2025-09-25 23:36 ` Dave Jiang
@ 2025-09-26 12:32 ` kernel test robot
2025-10-01 15:42 ` Jonathan Cameron
2025-10-03 20:11 ` Cheatham, Benjamin
3 siblings, 0 replies; 92+ messages in thread
From: kernel test robot @ 2025-09-26 12:32 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: oe-kbuild-all, linux-kernel, linux-pci, terry.bowman
Hi Terry,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 46037455cbb748c5e85071c95f2244e81986eb58]
url: https://github.com/intel-lab-lkp/linux/commits/Terry-Bowman/cxl-pci-Remove-unnecessary-CXL-Endpoint-handling-helper-functions/20250926-064816
base: 46037455cbb748c5e85071c95f2244e81986eb58
patch link: https://lore.kernel.org/r/20250925223440.3539069-7-terry.bowman%40amd.com
patch subject: [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors
config: microblaze-allnoconfig (https://download.01.org/0day-ci/archive/20250926/202509262001.AJLzM9is-lkp@intel.com/config)
compiler: microblaze-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250926/202509262001.AJLzM9is-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/202509262001.AJLzM9is-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from drivers/pci/of.c:18:
>> drivers/pci/pci.h:1208:69: warning: 'struct aer_err_info' declared inside parameter list will not be visible outside of this definition or declaration
1208 | static inline void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info) { }
| ^~~~~~~~~~~~
drivers/pci/pci.h:1215:45: warning: 'struct aer_err_info' declared inside parameter list will not be visible outside of this definition or declaration
1215 | static inline bool is_internal_error(struct aer_err_info *info) { return false; }
| ^~~~~~~~~~~~
vim +1208 drivers/pci/pci.h
1199
1200 #define PCI_CONF1_EXT_ADDRESS(bus, dev, func, reg) \
1201 (PCI_CONF1_ADDRESS(bus, dev, func, reg) | \
1202 PCI_CONF1_EXT_REG(reg))
1203
1204 #ifdef CONFIG_CXL_RCH_RAS
1205 void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info);
1206 void cxl_rch_enable_rcec(struct pci_dev *rcec);
1207 #else
> 1208 static inline void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info) { }
1209 static inline void cxl_rch_enable_rcec(struct pci_dev *rcec) { }
1210 #endif
1211
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors
2025-09-25 22:34 ` [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors Terry Bowman
2025-09-25 23:36 ` Dave Jiang
2025-09-26 12:32 ` kernel test robot
@ 2025-10-01 15:42 ` Jonathan Cameron
2025-10-03 20:11 ` Cheatham, Benjamin
3 siblings, 0 replies; 92+ messages in thread
From: Jonathan Cameron @ 2025-10-01 15:42 UTC (permalink / raw)
To: Terry Bowman
Cc: dave, dave.jiang, alison.schofield, dan.j.williams, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, linux-cxl,
alucerop, ira.weiny, linux-kernel, linux-pci
On Thu, 25 Sep 2025 17:34:21 -0500
Terry Bowman <terry.bowman@amd.com> wrote:
> The restricted CXL Host (RCH) AER error handling logic currently resides
> in the AER driver file, drivers/pci/pcie/aer.c. CXL specific changes are
> conditionally compiled using #ifdefs.
>
> Improve the AER driver maintainability by separating the RCH specific logic
> from the AER driver's core functionality and removing the ifdefs. Introduce
> drivers/pci/pcie/aer_cxl_rch.c for moving the RCH AER logic into.
> Conditionally compile the file using the CONFIG_CXL_RCH_RAS Kconfig.
>
> Move the CXL logic into the new file but leave helper functions in aer.c
> for now as they will be moved in future patch for CXL virtual hierarchy
> handling. Export the handler functions as needed. Export
> pci_aer_unmask_internal_errors() allowing for all subsystems to use.
> Avoid multiple declaration moves and export cxl_error_is_native() now to
> allow for cxl_core access.
>
> Inorder to maintain compilation after the move other changes are required.
> Change cxl_rch_handle_error() & cxl_rch_enable_rcec() to be non-static
> inorder for accessing from the AER driver in aer.c.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>
> ---
>
> Changes in v11->v12:
> - Rename drivers/pci/pcie/cxl_rch.c to drivers/pci/pcie/aer_cxl_rch.c (Lukas)
> - Removed forward declararation of 'struct aer_err_info' in pci/pci.h (Terry)
Unwise given the bot reply.
Fun is that it's only needed I think in the !CONFIG_CXL_RCH_RAS bit as that
can occur with !CONFIG_PCIE_AER.
Other than that, just a few trivial comments.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> diff --git a/drivers/pci/pcie/aer_cxl_rch.c b/drivers/pci/pcie/aer_cxl_rch.c
> new file mode 100644
> index 000000000000..bfe071eebf67
> --- /dev/null
> +++ b/drivers/pci/pcie/aer_cxl_rch.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright(c) 2025 AMD Corporation. All rights reserved. */
For a code move, the date at least should I think be a bit older.
> +
> +#include <linux/pci.h>
> +#include <linux/aer.h>
> +#include <linux/bitfield.h>
> +#include "../pci.h"
> +
> +static bool is_cxl_mem_dev(struct pci_dev *dev)
> +{
> + /*
> + * The capability, status, and control fields in Device 0,
> + * Function 0 DVSEC control the CXL functionality of the
> + * entire device (CXL 3.0, 8.1.3).
> + */
> + if (dev->devfn != PCI_DEVFN(0, 0))
> + return false;
> +
> + /*
> + * CXL Memory Devices must have the 502h class code set (CXL
> + * 3.0, 8.1.12.1).
> + */
> + if ((dev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> + return false;
> +
> + return true;
> +}
> +
> +static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
> +{
> + struct aer_err_info *info = (struct aer_err_info *)data;
> + const struct pci_error_handlers *err_handler;
> +
> + if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
> + return 0;
> +
> + /* Protect dev->driver */
> + device_lock(&dev->dev);
Unrelated but guard() might be nice to use here. Perhaps that's
in a later patch.
> +
> + err_handler = dev->driver ? dev->driver->err_handler : NULL;
> + if (!err_handler)
> + goto out;
> +
> + if (info->severity == AER_CORRECTABLE) {
> + if (err_handler->cor_error_detected)
> + err_handler->cor_error_detected(dev);
> + } else if (err_handler->error_detected) {
> + if (info->severity == AER_NONFATAL)
> + err_handler->error_detected(dev, pci_channel_io_normal);
> + else if (info->severity == AER_FATAL)
> + err_handler->error_detected(dev, pci_channel_io_frozen);
> + }
> +out:
> + device_unlock(&dev->dev);
> + return 0;
> +}
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors
2025-09-25 22:34 ` [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors Terry Bowman
` (2 preceding siblings ...)
2025-10-01 15:42 ` Jonathan Cameron
@ 2025-10-03 20:11 ` Cheatham, Benjamin
3 siblings, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:11 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-pci, dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> The restricted CXL Host (RCH) AER error handling logic currently resides
> in the AER driver file, drivers/pci/pcie/aer.c. CXL specific changes are
> conditionally compiled using #ifdefs.
>
> Improve the AER driver maintainability by separating the RCH specific logic
> from the AER driver's core functionality and removing the ifdefs. Introduce
> drivers/pci/pcie/aer_cxl_rch.c for moving the RCH AER logic into.
> Conditionally compile the file using the CONFIG_CXL_RCH_RAS Kconfig.
>
> Move the CXL logic into the new file but leave helper functions in aer.c
> for now as they will be moved in future patch for CXL virtual hierarchy
> handling. Export the handler functions as needed. Export
> pci_aer_unmask_internal_errors() allowing for all subsystems to use.
> Avoid multiple declaration moves and export cxl_error_is_native() now to
> allow for cxl_core access.
>
> Inorder to maintain compilation after the move other changes are required.
> Change cxl_rch_handle_error() & cxl_rch_enable_rcec() to be non-static
> inorder for accessing from the AER driver in aer.c.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>
> ---
With the build bot fix:
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 07/25] CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (5 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 06/25] CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-25 23:53 ` Dave Jiang
2025-10-01 15:58 ` Jonathan Cameron
2025-09-25 22:34 ` [PATCH v12 08/25] PCI/CXL: Introduce pcie_is_cxl() Terry Bowman
` (17 subsequent siblings)
24 siblings, 2 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
The CXL DVSECs are currently defined in cxl/core/cxlpci.h. These are not
accessible to other subsystems.
Change DVSEC name formatting to follow the existing PCI format in
pci_regs.h. The current format uses CXL_DVSEC_XYZ. Change to be PCI_DVSEC_CXL_XYZ.
Reuse the existing formatting.
Update existing occurrences to match the name change.
Update the inline documentation to refer to latest CXL spec version.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
----
Changes in v11 -> v12:
- Change formatting to be same as existing definitions
- Change GENMASK() -> __GENMASK() and BIT() to _BITUL()
Changes in v10 -> v11:
- New commit
---
drivers/cxl/core/pci.c | 62 +++++++++++++++++-----------------
drivers/cxl/core/regs.c | 12 +++----
drivers/cxl/cxlpci.h | 53 -----------------------------
drivers/cxl/pci.c | 2 +-
drivers/pci/pci.c | 18 +++++-----
include/uapi/linux/pci_regs.h | 63 ++++++++++++++++++++++++++++++++---
6 files changed, 107 insertions(+), 103 deletions(-)
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index a009a51cb0de..a74a39bd909c 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -157,19 +157,19 @@ static int cxl_dvsec_mem_range_valid(struct cxl_dev_state *cxlds, int id)
int rc, i;
u32 temp;
- if (id > CXL_DVSEC_RANGE_MAX)
+ if (id > PCI_DVSEC_CXL_RANGE_MAX)
return -EINVAL;
/* Check MEM INFO VALID bit first, give up after 1s */
i = 1;
do {
rc = pci_read_config_dword(pdev,
- d + CXL_DVSEC_RANGE_SIZE_LOW(id),
+ d + PCI_DVSEC_CXL_RANGE_SIZE_LOW(id),
&temp);
if (rc)
return rc;
- valid = FIELD_GET(CXL_DVSEC_MEM_INFO_VALID, temp);
+ valid = FIELD_GET(PCI_DVSEC_CXL_MEM_INFO_VALID, temp);
if (valid)
break;
msleep(1000);
@@ -193,17 +193,17 @@ static int cxl_dvsec_mem_range_active(struct cxl_dev_state *cxlds, int id)
int rc, i;
u32 temp;
- if (id > CXL_DVSEC_RANGE_MAX)
+ if (id > PCI_DVSEC_CXL_RANGE_MAX)
return -EINVAL;
/* Check MEM ACTIVE bit, up to 60s timeout by default */
for (i = media_ready_timeout; i; i--) {
rc = pci_read_config_dword(
- pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(id), &temp);
+ pdev, d + PCI_DVSEC_CXL_RANGE_SIZE_LOW(id), &temp);
if (rc)
return rc;
- active = FIELD_GET(CXL_DVSEC_MEM_ACTIVE, temp);
+ active = FIELD_GET(PCI_DVSEC_CXL_MEM_ACTIVE, temp);
if (active)
break;
msleep(1000);
@@ -232,11 +232,11 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds)
u16 cap;
rc = pci_read_config_word(pdev,
- d + CXL_DVSEC_CAP_OFFSET, &cap);
+ d + PCI_DVSEC_CXL_CAP_OFFSET, &cap);
if (rc)
return rc;
- hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap);
+ hdm_count = FIELD_GET(PCI_DVSEC_CXL_HDM_COUNT_MASK, cap);
for (i = 0; i < hdm_count; i++) {
rc = cxl_dvsec_mem_range_valid(cxlds, i);
if (rc)
@@ -264,16 +264,16 @@ static int cxl_set_mem_enable(struct cxl_dev_state *cxlds, u16 val)
u16 ctrl;
int rc;
- rc = pci_read_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, &ctrl);
+ rc = pci_read_config_word(pdev, d + PCI_DVSEC_CXL_CTRL_OFFSET, &ctrl);
if (rc < 0)
return rc;
- if ((ctrl & CXL_DVSEC_MEM_ENABLE) == val)
+ if ((ctrl & PCI_DVSEC_CXL_MEM_ENABLE) == val)
return 1;
- ctrl &= ~CXL_DVSEC_MEM_ENABLE;
+ ctrl &= ~PCI_DVSEC_CXL_MEM_ENABLE;
ctrl |= val;
- rc = pci_write_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, ctrl);
+ rc = pci_write_config_word(pdev, d + PCI_DVSEC_CXL_CTRL_OFFSET, ctrl);
if (rc < 0)
return rc;
@@ -289,7 +289,7 @@ static int devm_cxl_enable_mem(struct device *host, struct cxl_dev_state *cxlds)
{
int rc;
- rc = cxl_set_mem_enable(cxlds, CXL_DVSEC_MEM_ENABLE);
+ rc = cxl_set_mem_enable(cxlds, PCI_DVSEC_CXL_MEM_ENABLE);
if (rc < 0)
return rc;
if (rc > 0)
@@ -351,11 +351,11 @@ int cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds,
return -ENXIO;
}
- rc = pci_read_config_word(pdev, d + CXL_DVSEC_CAP_OFFSET, &cap);
+ rc = pci_read_config_word(pdev, d + PCI_DVSEC_CXL_CAP_OFFSET, &cap);
if (rc)
return rc;
- if (!(cap & CXL_DVSEC_MEM_CAPABLE)) {
+ if (!(cap & PCI_DVSEC_CXL_MEM_CAPABLE)) {
dev_dbg(dev, "Not MEM Capable\n");
return -ENXIO;
}
@@ -366,7 +366,7 @@ int cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds,
* driver is for a spec defined class code which must be CXL.mem
* capable, there is no point in continuing to enable CXL.mem.
*/
- hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap);
+ hdm_count = FIELD_GET(PCI_DVSEC_CXL_HDM_COUNT_MASK, cap);
if (!hdm_count || hdm_count > 2)
return -EINVAL;
@@ -375,11 +375,11 @@ int cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds,
* disabled, and they will remain moot after the HDM Decoder
* capability is enabled.
*/
- rc = pci_read_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, &ctrl);
+ rc = pci_read_config_word(pdev, d + PCI_DVSEC_CXL_CTRL_OFFSET, &ctrl);
if (rc)
return rc;
- info->mem_enabled = FIELD_GET(CXL_DVSEC_MEM_ENABLE, ctrl);
+ info->mem_enabled = FIELD_GET(PCI_DVSEC_CXL_MEM_ENABLE, ctrl);
if (!info->mem_enabled)
return 0;
@@ -392,35 +392,35 @@ int cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds,
return rc;
rc = pci_read_config_dword(
- pdev, d + CXL_DVSEC_RANGE_SIZE_HIGH(i), &temp);
+ pdev, d + PCI_DVSEC_CXL_RANGE_SIZE_HIGH(i), &temp);
if (rc)
return rc;
size = (u64)temp << 32;
rc = pci_read_config_dword(
- pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(i), &temp);
+ pdev, d + PCI_DVSEC_CXL_RANGE_SIZE_LOW(i), &temp);
if (rc)
return rc;
- size |= temp & CXL_DVSEC_MEM_SIZE_LOW_MASK;
+ size |= temp & PCI_DVSEC_CXL_MEM_SIZE_LOW_MASK;
if (!size) {
continue;
}
rc = pci_read_config_dword(
- pdev, d + CXL_DVSEC_RANGE_BASE_HIGH(i), &temp);
+ pdev, d + PCI_DVSEC_CXL_RANGE_BASE_HIGH(i), &temp);
if (rc)
return rc;
base = (u64)temp << 32;
rc = pci_read_config_dword(
- pdev, d + CXL_DVSEC_RANGE_BASE_LOW(i), &temp);
+ pdev, d + PCI_DVSEC_CXL_RANGE_BASE_LOW(i), &temp);
if (rc)
return rc;
- base |= temp & CXL_DVSEC_MEM_BASE_LOW_MASK;
+ base |= temp & PCI_DVSEC_CXL_MEM_BASE_LOW_MASK;
info->dvsec_range[ranges++] = (struct range) {
.start = base,
@@ -828,7 +828,7 @@ u16 cxl_gpf_get_dvsec(struct device *dev)
is_port = false;
dvsec = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL,
- is_port ? CXL_DVSEC_PORT_GPF : CXL_DVSEC_DEVICE_GPF);
+ is_port ? PCI_DVSEC_CXL_PORT_GPF : PCI_DVSEC_CXL_DEVICE_GPF);
if (!dvsec)
dev_warn(dev, "%s GPF DVSEC not present\n",
is_port ? "Port" : "Device");
@@ -844,14 +844,14 @@ static int update_gpf_port_dvsec(struct pci_dev *pdev, int dvsec, int phase)
switch (phase) {
case 1:
- offset = CXL_DVSEC_PORT_GPF_PHASE_1_CONTROL_OFFSET;
- base = CXL_DVSEC_PORT_GPF_PHASE_1_TMO_BASE_MASK;
- scale = CXL_DVSEC_PORT_GPF_PHASE_1_TMO_SCALE_MASK;
+ offset = PCI_DVSEC_CXL_PORT_GPF_PHASE_1_CONTROL_OFFSET;
+ base = PCI_DVSEC_CXL_PORT_GPF_PHASE_1_TMO_BASE_MASK;
+ scale = PCI_DVSEC_CXL_PORT_GPF_PHASE_1_TMO_SCALE_MASK;
break;
case 2:
- offset = CXL_DVSEC_PORT_GPF_PHASE_2_CONTROL_OFFSET;
- base = CXL_DVSEC_PORT_GPF_PHASE_2_TMO_BASE_MASK;
- scale = CXL_DVSEC_PORT_GPF_PHASE_2_TMO_SCALE_MASK;
+ offset = PCI_DVSEC_CXL_PORT_GPF_PHASE_2_CONTROL_OFFSET;
+ base = PCI_DVSEC_CXL_PORT_GPF_PHASE_2_TMO_BASE_MASK;
+ scale = PCI_DVSEC_CXL_PORT_GPF_PHASE_2_TMO_SCALE_MASK;
break;
default:
return -EINVAL;
diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index 5ca7b0eed568..fb70ffbba72d 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -271,10 +271,10 @@ EXPORT_SYMBOL_NS_GPL(cxl_map_device_regs, "CXL");
static bool cxl_decode_regblock(struct pci_dev *pdev, u32 reg_lo, u32 reg_hi,
struct cxl_register_map *map)
{
- u8 reg_type = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BLOCK_ID_MASK, reg_lo);
- int bar = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BIR_MASK, reg_lo);
+ u8 reg_type = FIELD_GET(PCI_DVSEC_CXL_REG_LOCATOR_BLOCK_ID_MASK, reg_lo);
+ int bar = FIELD_GET(PCI_DVSEC_CXL_REG_LOCATOR_BIR_MASK, reg_lo);
u64 offset = ((u64)reg_hi << 32) |
- (reg_lo & CXL_DVSEC_REG_LOCATOR_BLOCK_OFF_LOW_MASK);
+ (reg_lo & PCI_DVSEC_CXL_REG_LOCATOR_BLOCK_OFF_LOW_MASK);
if (offset > pci_resource_len(pdev, bar)) {
dev_warn(&pdev->dev,
@@ -311,15 +311,15 @@ static int __cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_ty
};
regloc = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL,
- CXL_DVSEC_REG_LOCATOR);
+ PCI_DVSEC_CXL_REG_LOCATOR);
if (!regloc)
return -ENXIO;
pci_read_config_dword(pdev, regloc + PCI_DVSEC_HEADER1, ®loc_size);
regloc_size = FIELD_GET(PCI_DVSEC_HEADER1_LENGTH_MASK, regloc_size);
- regloc += CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET;
- regblocks = (regloc_size - CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET) / 8;
+ regloc += PCI_DVSEC_CXL_REG_LOCATOR_BLOCK1_OFFSET;
+ regblocks = (regloc_size - PCI_DVSEC_CXL_REG_LOCATOR_BLOCK1_OFFSET) / 8;
for (i = 0; i < regblocks; i++, regloc += 8) {
u32 reg_lo, reg_hi;
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 970e84cf49e9..0c8b6ee7b6de 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 bd100ac31672..bd95be1f3d5c 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -933,7 +933,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
cxlds->rcd = is_cxl_restricted(pdev);
cxlds->serial = pci_get_dsn(pdev);
cxlds->cxl_dvsec = pci_find_dvsec_capability(
- pdev, PCI_VENDOR_ID_CXL, CXL_DVSEC_PCIE_DEVICE);
+ pdev, PCI_VENDOR_ID_CXL, PCI_DVSEC_CXL_DEVICE);
if (!cxlds->cxl_dvsec)
dev_warn(&pdev->dev,
"Device DVSEC not present, skip CXL.mem init\n");
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b0f4d98036cd..1a4f61caa0db 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -5041,7 +5041,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);
+ PCI_DVSEC_CXL_PORT_EXT);
}
static bool cxl_sbr_masked(struct pci_dev *dev)
@@ -5053,7 +5053,9 @@ 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 + PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET,
+ ®);
if (rc || PCI_POSSIBLE_ERROR(reg))
return false;
@@ -5062,7 +5064,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 & PCI_DVSEC_CXL_PORT_EXT_CTL_UNMASK_SBR)
return false;
return true;
@@ -5107,22 +5109,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 + PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET, ®);
if (rc)
return -ENOTTY;
- if (reg & PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR) {
+ if (reg & PCI_DVSEC_CXL_PORT_EXT_CTL_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 | PCI_DVSEC_CXL_PORT_EXT_CTL_UNMASK_SBR;
+ pci_write_config_word(bridge, dvsec + PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET,
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 + PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET,
reg);
return rc;
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index f5b17745de60..bd03799612d3 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -1234,9 +1234,64 @@
/* Deprecated old name, replaced with PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE */
#define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE
-/* 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
+/* Compute Express Link (CXL r3.2, sec 8.1)
+ *
+ * Note that CXL DVSEC id 3 and 7 to be ignored when the CXL link state
+ * is "disconnected" (CXL r3.2, sec 9.12.3). Re-enumerate these
+ * registers on downstream link-up events.
+ */
+
+#define PCI_DVSEC_HEADER1_LENGTH_MASK __GENMASK(31, 20)
+
+/* CXL 3.2 8.1.3: PCIe DVSEC for CXL Device */
+#define PCI_DVSEC_CXL_DEVICE 0
+#define PCI_DVSEC_CXL_CAP_OFFSET 0xA
+#define PCI_DVSEC_CXL_MEM_CAPABLE _BITUL(2)
+#define PCI_DVSEC_CXL_HDM_COUNT_MASK __GENMASK(5, 4)
+#define PCI_DVSEC_CXL_CTRL_OFFSET 0xC
+#define PCI_DVSEC_CXL_MEM_ENABLE _BITUL(2)
+#define PCI_DVSEC_CXL_RANGE_SIZE_HIGH(i) (0x18 + (i * 0x10))
+#define PCI_DVSEC_CXL_RANGE_SIZE_LOW(i) (0x1C + (i * 0x10))
+#define PCI_DVSEC_CXL_MEM_INFO_VALID _BITUL(0)
+#define PCI_DVSEC_CXL_MEM_ACTIVE _BITUL(1)
+#define PCI_DVSEC_CXL_MEM_SIZE_LOW_MASK __GENMASK(31, 28)
+#define PCI_DVSEC_CXL_RANGE_BASE_HIGH(i) (0x20 + (i * 0x10))
+#define PCI_DVSEC_CXL_RANGE_BASE_LOW(i) (0x24 + (i * 0x10))
+#define PCI_DVSEC_CXL_MEM_BASE_LOW_MASK __GENMASK(31, 28)
+
+#define PCI_DVSEC_CXL_RANGE_MAX 2
+
+/* CXL 3.2 8.1.4: Non-CXL Function Map DVSEC */
+#define PCI_DVSEC_CXL_FUNCTION_MAP 2
+
+/* CXL 3.2 8.1.5: Extensions DVSEC for Ports */
+#define PCI_DVSEC_CXL_PORT_EXT 3
+#define PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET 0x0c
+#define PCI_DVSEC_CXL_PORT_EXT_CTL_UNMASK_SBR 0x00000001
+
+/* CXL 3.2 8.1.6: GPF DVSEC for CXL Port */
+#define PCI_DVSEC_CXL_PORT_GPF 4
+#define PCI_DVSEC_CXL_PORT_GPF_PHASE_1_CONTROL_OFFSET 0x0C
+#define PCI_DVSEC_CXL_PORT_GPF_PHASE_1_TMO_BASE_MASK __GENMASK(3, 0)
+#define PCI_DVSEC_CXL_PORT_GPF_PHASE_1_TMO_SCALE_MASK __GENMASK(11, 8)
+#define PCI_DVSEC_CXL_PORT_GPF_PHASE_2_CONTROL_OFFSET 0xE
+#define PCI_DVSEC_CXL_PORT_GPF_PHASE_2_TMO_BASE_MASK __GENMASK(3, 0)
+#define PCI_DVSEC_CXL_PORT_GPF_PHASE_2_TMO_SCALE_MASK __GENMASK(11, 8)
+
+/* CXL 3.2 8.1.7: GPF DVSEC for CXL Device */
+#define PCI_DVSEC_CXL_DEVICE_GPF 5
+
+/* CXL 3.2 8.1.8: PCIe DVSEC for Flex Bus Port */
+#define PCI_DVSEC_CXL_FLEXBUS_PORT 7
+#define PCI_DVSEC_CXL_FLEXBUS_STATUS_OFFSET 0xE
+#define PCI_DVSEC_CXL_FLEXBUS_STATUS_CACHE_MASK _BITUL(0)
+#define PCI_DVSEC_CXL_FLEXBUS_STATUS_MEM_MASK _BITUL(2)
+
+/* CXL 3.2 8.1.9: Register Locator DVSEC */
+#define PCI_DVSEC_CXL_REG_LOCATOR 8
+#define PCI_DVSEC_CXL_REG_LOCATOR_BLOCK1_OFFSET 0xC
+#define PCI_DVSEC_CXL_REG_LOCATOR_BIR_MASK __GENMASK(2, 0)
+#define PCI_DVSEC_CXL_REG_LOCATOR_BLOCK_ID_MASK __GENMASK(15, 8)
+#define PCI_DVSEC_CXL_REG_LOCATOR_BLOCK_OFF_LOW_MASK __GENMASK(31, 16)
#endif /* LINUX_PCI_REGS_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 07/25] CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h
2025-09-25 22:34 ` [PATCH v12 07/25] CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h Terry Bowman
@ 2025-09-25 23:53 ` Dave Jiang
2025-10-01 15:58 ` Jonathan Cameron
1 sibling, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-25 23:53 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> The CXL DVSECs are currently defined in cxl/core/cxlpci.h. These are not
> accessible to other subsystems.
>
> Change DVSEC name formatting to follow the existing PCI format in
> pci_regs.h. The current format uses CXL_DVSEC_XYZ. Change to be PCI_DVSEC_CXL_XYZ.
> Reuse the existing formatting.
>
> Update existing occurrences to match the name change.
>
> Update the inline documentation to refer to latest CXL spec version.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> ----
>
> Changes in v11 -> v12:
> - Change formatting to be same as existing definitions
> - Change GENMASK() -> __GENMASK() and BIT() to _BITUL()
>
> Changes in v10 -> v11:
> - New commit
> ---
> drivers/cxl/core/pci.c | 62 +++++++++++++++++-----------------
> drivers/cxl/core/regs.c | 12 +++----
> drivers/cxl/cxlpci.h | 53 -----------------------------
> drivers/cxl/pci.c | 2 +-
> drivers/pci/pci.c | 18 +++++-----
> include/uapi/linux/pci_regs.h | 63 ++++++++++++++++++++++++++++++++---
> 6 files changed, 107 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index a009a51cb0de..a74a39bd909c 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -157,19 +157,19 @@ static int cxl_dvsec_mem_range_valid(struct cxl_dev_state *cxlds, int id)
> int rc, i;
> u32 temp;
>
> - if (id > CXL_DVSEC_RANGE_MAX)
> + if (id > PCI_DVSEC_CXL_RANGE_MAX)
> return -EINVAL;
>
> /* Check MEM INFO VALID bit first, give up after 1s */
> i = 1;
> do {
> rc = pci_read_config_dword(pdev,
> - d + CXL_DVSEC_RANGE_SIZE_LOW(id),
> + d + PCI_DVSEC_CXL_RANGE_SIZE_LOW(id),
> &temp);
> if (rc)
> return rc;
>
> - valid = FIELD_GET(CXL_DVSEC_MEM_INFO_VALID, temp);
> + valid = FIELD_GET(PCI_DVSEC_CXL_MEM_INFO_VALID, temp);
> if (valid)
> break;
> msleep(1000);
> @@ -193,17 +193,17 @@ static int cxl_dvsec_mem_range_active(struct cxl_dev_state *cxlds, int id)
> int rc, i;
> u32 temp;
>
> - if (id > CXL_DVSEC_RANGE_MAX)
> + if (id > PCI_DVSEC_CXL_RANGE_MAX)
> return -EINVAL;
>
> /* Check MEM ACTIVE bit, up to 60s timeout by default */
> for (i = media_ready_timeout; i; i--) {
> rc = pci_read_config_dword(
> - pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(id), &temp);
> + pdev, d + PCI_DVSEC_CXL_RANGE_SIZE_LOW(id), &temp);
> if (rc)
> return rc;
>
> - active = FIELD_GET(CXL_DVSEC_MEM_ACTIVE, temp);
> + active = FIELD_GET(PCI_DVSEC_CXL_MEM_ACTIVE, temp);
> if (active)
> break;
> msleep(1000);
> @@ -232,11 +232,11 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds)
> u16 cap;
>
> rc = pci_read_config_word(pdev,
> - d + CXL_DVSEC_CAP_OFFSET, &cap);
> + d + PCI_DVSEC_CXL_CAP_OFFSET, &cap);
> if (rc)
> return rc;
>
> - hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap);
> + hdm_count = FIELD_GET(PCI_DVSEC_CXL_HDM_COUNT_MASK, cap);
> for (i = 0; i < hdm_count; i++) {
> rc = cxl_dvsec_mem_range_valid(cxlds, i);
> if (rc)
> @@ -264,16 +264,16 @@ static int cxl_set_mem_enable(struct cxl_dev_state *cxlds, u16 val)
> u16 ctrl;
> int rc;
>
> - rc = pci_read_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, &ctrl);
> + rc = pci_read_config_word(pdev, d + PCI_DVSEC_CXL_CTRL_OFFSET, &ctrl);
> if (rc < 0)
> return rc;
>
> - if ((ctrl & CXL_DVSEC_MEM_ENABLE) == val)
> + if ((ctrl & PCI_DVSEC_CXL_MEM_ENABLE) == val)
> return 1;
> - ctrl &= ~CXL_DVSEC_MEM_ENABLE;
> + ctrl &= ~PCI_DVSEC_CXL_MEM_ENABLE;
> ctrl |= val;
>
> - rc = pci_write_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, ctrl);
> + rc = pci_write_config_word(pdev, d + PCI_DVSEC_CXL_CTRL_OFFSET, ctrl);
> if (rc < 0)
> return rc;
>
> @@ -289,7 +289,7 @@ static int devm_cxl_enable_mem(struct device *host, struct cxl_dev_state *cxlds)
> {
> int rc;
>
> - rc = cxl_set_mem_enable(cxlds, CXL_DVSEC_MEM_ENABLE);
> + rc = cxl_set_mem_enable(cxlds, PCI_DVSEC_CXL_MEM_ENABLE);
> if (rc < 0)
> return rc;
> if (rc > 0)
> @@ -351,11 +351,11 @@ int cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds,
> return -ENXIO;
> }
>
> - rc = pci_read_config_word(pdev, d + CXL_DVSEC_CAP_OFFSET, &cap);
> + rc = pci_read_config_word(pdev, d + PCI_DVSEC_CXL_CAP_OFFSET, &cap);
> if (rc)
> return rc;
>
> - if (!(cap & CXL_DVSEC_MEM_CAPABLE)) {
> + if (!(cap & PCI_DVSEC_CXL_MEM_CAPABLE)) {
> dev_dbg(dev, "Not MEM Capable\n");
> return -ENXIO;
> }
> @@ -366,7 +366,7 @@ int cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds,
> * driver is for a spec defined class code which must be CXL.mem
> * capable, there is no point in continuing to enable CXL.mem.
> */
> - hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap);
> + hdm_count = FIELD_GET(PCI_DVSEC_CXL_HDM_COUNT_MASK, cap);
> if (!hdm_count || hdm_count > 2)
> return -EINVAL;
>
> @@ -375,11 +375,11 @@ int cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds,
> * disabled, and they will remain moot after the HDM Decoder
> * capability is enabled.
> */
> - rc = pci_read_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, &ctrl);
> + rc = pci_read_config_word(pdev, d + PCI_DVSEC_CXL_CTRL_OFFSET, &ctrl);
> if (rc)
> return rc;
>
> - info->mem_enabled = FIELD_GET(CXL_DVSEC_MEM_ENABLE, ctrl);
> + info->mem_enabled = FIELD_GET(PCI_DVSEC_CXL_MEM_ENABLE, ctrl);
> if (!info->mem_enabled)
> return 0;
>
> @@ -392,35 +392,35 @@ int cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds,
> return rc;
>
> rc = pci_read_config_dword(
> - pdev, d + CXL_DVSEC_RANGE_SIZE_HIGH(i), &temp);
> + pdev, d + PCI_DVSEC_CXL_RANGE_SIZE_HIGH(i), &temp);
> if (rc)
> return rc;
>
> size = (u64)temp << 32;
>
> rc = pci_read_config_dword(
> - pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(i), &temp);
> + pdev, d + PCI_DVSEC_CXL_RANGE_SIZE_LOW(i), &temp);
> if (rc)
> return rc;
>
> - size |= temp & CXL_DVSEC_MEM_SIZE_LOW_MASK;
> + size |= temp & PCI_DVSEC_CXL_MEM_SIZE_LOW_MASK;
> if (!size) {
> continue;
> }
>
> rc = pci_read_config_dword(
> - pdev, d + CXL_DVSEC_RANGE_BASE_HIGH(i), &temp);
> + pdev, d + PCI_DVSEC_CXL_RANGE_BASE_HIGH(i), &temp);
> if (rc)
> return rc;
>
> base = (u64)temp << 32;
>
> rc = pci_read_config_dword(
> - pdev, d + CXL_DVSEC_RANGE_BASE_LOW(i), &temp);
> + pdev, d + PCI_DVSEC_CXL_RANGE_BASE_LOW(i), &temp);
> if (rc)
> return rc;
>
> - base |= temp & CXL_DVSEC_MEM_BASE_LOW_MASK;
> + base |= temp & PCI_DVSEC_CXL_MEM_BASE_LOW_MASK;
>
> info->dvsec_range[ranges++] = (struct range) {
> .start = base,
> @@ -828,7 +828,7 @@ u16 cxl_gpf_get_dvsec(struct device *dev)
> is_port = false;
>
> dvsec = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL,
> - is_port ? CXL_DVSEC_PORT_GPF : CXL_DVSEC_DEVICE_GPF);
> + is_port ? PCI_DVSEC_CXL_PORT_GPF : PCI_DVSEC_CXL_DEVICE_GPF);
> if (!dvsec)
> dev_warn(dev, "%s GPF DVSEC not present\n",
> is_port ? "Port" : "Device");
> @@ -844,14 +844,14 @@ static int update_gpf_port_dvsec(struct pci_dev *pdev, int dvsec, int phase)
>
> switch (phase) {
> case 1:
> - offset = CXL_DVSEC_PORT_GPF_PHASE_1_CONTROL_OFFSET;
> - base = CXL_DVSEC_PORT_GPF_PHASE_1_TMO_BASE_MASK;
> - scale = CXL_DVSEC_PORT_GPF_PHASE_1_TMO_SCALE_MASK;
> + offset = PCI_DVSEC_CXL_PORT_GPF_PHASE_1_CONTROL_OFFSET;
> + base = PCI_DVSEC_CXL_PORT_GPF_PHASE_1_TMO_BASE_MASK;
> + scale = PCI_DVSEC_CXL_PORT_GPF_PHASE_1_TMO_SCALE_MASK;
> break;
> case 2:
> - offset = CXL_DVSEC_PORT_GPF_PHASE_2_CONTROL_OFFSET;
> - base = CXL_DVSEC_PORT_GPF_PHASE_2_TMO_BASE_MASK;
> - scale = CXL_DVSEC_PORT_GPF_PHASE_2_TMO_SCALE_MASK;
> + offset = PCI_DVSEC_CXL_PORT_GPF_PHASE_2_CONTROL_OFFSET;
> + base = PCI_DVSEC_CXL_PORT_GPF_PHASE_2_TMO_BASE_MASK;
> + scale = PCI_DVSEC_CXL_PORT_GPF_PHASE_2_TMO_SCALE_MASK;
> break;
> default:
> return -EINVAL;
> diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
> index 5ca7b0eed568..fb70ffbba72d 100644
> --- a/drivers/cxl/core/regs.c
> +++ b/drivers/cxl/core/regs.c
> @@ -271,10 +271,10 @@ EXPORT_SYMBOL_NS_GPL(cxl_map_device_regs, "CXL");
> static bool cxl_decode_regblock(struct pci_dev *pdev, u32 reg_lo, u32 reg_hi,
> struct cxl_register_map *map)
> {
> - u8 reg_type = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BLOCK_ID_MASK, reg_lo);
> - int bar = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BIR_MASK, reg_lo);
> + u8 reg_type = FIELD_GET(PCI_DVSEC_CXL_REG_LOCATOR_BLOCK_ID_MASK, reg_lo);
> + int bar = FIELD_GET(PCI_DVSEC_CXL_REG_LOCATOR_BIR_MASK, reg_lo);
> u64 offset = ((u64)reg_hi << 32) |
> - (reg_lo & CXL_DVSEC_REG_LOCATOR_BLOCK_OFF_LOW_MASK);
> + (reg_lo & PCI_DVSEC_CXL_REG_LOCATOR_BLOCK_OFF_LOW_MASK);
>
> if (offset > pci_resource_len(pdev, bar)) {
> dev_warn(&pdev->dev,
> @@ -311,15 +311,15 @@ static int __cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_ty
> };
>
> regloc = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL,
> - CXL_DVSEC_REG_LOCATOR);
> + PCI_DVSEC_CXL_REG_LOCATOR);
> if (!regloc)
> return -ENXIO;
>
> pci_read_config_dword(pdev, regloc + PCI_DVSEC_HEADER1, ®loc_size);
> regloc_size = FIELD_GET(PCI_DVSEC_HEADER1_LENGTH_MASK, regloc_size);
>
> - regloc += CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET;
> - regblocks = (regloc_size - CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET) / 8;
> + regloc += PCI_DVSEC_CXL_REG_LOCATOR_BLOCK1_OFFSET;
> + regblocks = (regloc_size - PCI_DVSEC_CXL_REG_LOCATOR_BLOCK1_OFFSET) / 8;
>
> for (i = 0; i < regblocks; i++, regloc += 8) {
> u32 reg_lo, reg_hi;
> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
> index 970e84cf49e9..0c8b6ee7b6de 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 bd100ac31672..bd95be1f3d5c 100644
> --- a/drivers/cxl/pci.c
> +++ b/drivers/cxl/pci.c
> @@ -933,7 +933,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> cxlds->rcd = is_cxl_restricted(pdev);
> cxlds->serial = pci_get_dsn(pdev);
> cxlds->cxl_dvsec = pci_find_dvsec_capability(
> - pdev, PCI_VENDOR_ID_CXL, CXL_DVSEC_PCIE_DEVICE);
> + pdev, PCI_VENDOR_ID_CXL, PCI_DVSEC_CXL_DEVICE);
> if (!cxlds->cxl_dvsec)
> dev_warn(&pdev->dev,
> "Device DVSEC not present, skip CXL.mem init\n");
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index b0f4d98036cd..1a4f61caa0db 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -5041,7 +5041,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);
> + PCI_DVSEC_CXL_PORT_EXT);
> }
>
> static bool cxl_sbr_masked(struct pci_dev *dev)
> @@ -5053,7 +5053,9 @@ 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 + PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET,
> + ®);
> if (rc || PCI_POSSIBLE_ERROR(reg))
> return false;
>
> @@ -5062,7 +5064,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 & PCI_DVSEC_CXL_PORT_EXT_CTL_UNMASK_SBR)
> return false;
>
> return true;
> @@ -5107,22 +5109,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 + PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET, ®);
> if (rc)
> return -ENOTTY;
>
> - if (reg & PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR) {
> + if (reg & PCI_DVSEC_CXL_PORT_EXT_CTL_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 | PCI_DVSEC_CXL_PORT_EXT_CTL_UNMASK_SBR;
> + pci_write_config_word(bridge, dvsec + PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET,
> 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 + PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET,
> reg);
>
> return rc;
> diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
> index f5b17745de60..bd03799612d3 100644
> --- a/include/uapi/linux/pci_regs.h
> +++ b/include/uapi/linux/pci_regs.h
> @@ -1234,9 +1234,64 @@
> /* Deprecated old name, replaced with PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE */
> #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE
>
> -/* 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
> +/* Compute Express Link (CXL r3.2, sec 8.1)
> + *
> + * Note that CXL DVSEC id 3 and 7 to be ignored when the CXL link state
> + * is "disconnected" (CXL r3.2, sec 9.12.3). Re-enumerate these
> + * registers on downstream link-up events.
> + */
> +
> +#define PCI_DVSEC_HEADER1_LENGTH_MASK __GENMASK(31, 20)
> +
> +/* CXL 3.2 8.1.3: PCIe DVSEC for CXL Device */
> +#define PCI_DVSEC_CXL_DEVICE 0
> +#define PCI_DVSEC_CXL_CAP_OFFSET 0xA
> +#define PCI_DVSEC_CXL_MEM_CAPABLE _BITUL(2)
> +#define PCI_DVSEC_CXL_HDM_COUNT_MASK __GENMASK(5, 4)
> +#define PCI_DVSEC_CXL_CTRL_OFFSET 0xC
> +#define PCI_DVSEC_CXL_MEM_ENABLE _BITUL(2)
> +#define PCI_DVSEC_CXL_RANGE_SIZE_HIGH(i) (0x18 + (i * 0x10))
> +#define PCI_DVSEC_CXL_RANGE_SIZE_LOW(i) (0x1C + (i * 0x10))
> +#define PCI_DVSEC_CXL_MEM_INFO_VALID _BITUL(0)
> +#define PCI_DVSEC_CXL_MEM_ACTIVE _BITUL(1)
> +#define PCI_DVSEC_CXL_MEM_SIZE_LOW_MASK __GENMASK(31, 28)
> +#define PCI_DVSEC_CXL_RANGE_BASE_HIGH(i) (0x20 + (i * 0x10))
> +#define PCI_DVSEC_CXL_RANGE_BASE_LOW(i) (0x24 + (i * 0x10))
> +#define PCI_DVSEC_CXL_MEM_BASE_LOW_MASK __GENMASK(31, 28)
> +
> +#define PCI_DVSEC_CXL_RANGE_MAX 2
> +
> +/* CXL 3.2 8.1.4: Non-CXL Function Map DVSEC */
> +#define PCI_DVSEC_CXL_FUNCTION_MAP 2
> +
> +/* CXL 3.2 8.1.5: Extensions DVSEC for Ports */
> +#define PCI_DVSEC_CXL_PORT_EXT 3
> +#define PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET 0x0c
> +#define PCI_DVSEC_CXL_PORT_EXT_CTL_UNMASK_SBR 0x00000001
> +
> +/* CXL 3.2 8.1.6: GPF DVSEC for CXL Port */
> +#define PCI_DVSEC_CXL_PORT_GPF 4
> +#define PCI_DVSEC_CXL_PORT_GPF_PHASE_1_CONTROL_OFFSET 0x0C
> +#define PCI_DVSEC_CXL_PORT_GPF_PHASE_1_TMO_BASE_MASK __GENMASK(3, 0)
> +#define PCI_DVSEC_CXL_PORT_GPF_PHASE_1_TMO_SCALE_MASK __GENMASK(11, 8)
> +#define PCI_DVSEC_CXL_PORT_GPF_PHASE_2_CONTROL_OFFSET 0xE
> +#define PCI_DVSEC_CXL_PORT_GPF_PHASE_2_TMO_BASE_MASK __GENMASK(3, 0)
> +#define PCI_DVSEC_CXL_PORT_GPF_PHASE_2_TMO_SCALE_MASK __GENMASK(11, 8)
> +
> +/* CXL 3.2 8.1.7: GPF DVSEC for CXL Device */
> +#define PCI_DVSEC_CXL_DEVICE_GPF 5
> +
> +/* CXL 3.2 8.1.8: PCIe DVSEC for Flex Bus Port */
> +#define PCI_DVSEC_CXL_FLEXBUS_PORT 7
> +#define PCI_DVSEC_CXL_FLEXBUS_STATUS_OFFSET 0xE
> +#define PCI_DVSEC_CXL_FLEXBUS_STATUS_CACHE_MASK _BITUL(0)
> +#define PCI_DVSEC_CXL_FLEXBUS_STATUS_MEM_MASK _BITUL(2)
> +
> +/* CXL 3.2 8.1.9: Register Locator DVSEC */
> +#define PCI_DVSEC_CXL_REG_LOCATOR 8
> +#define PCI_DVSEC_CXL_REG_LOCATOR_BLOCK1_OFFSET 0xC
> +#define PCI_DVSEC_CXL_REG_LOCATOR_BIR_MASK __GENMASK(2, 0)
> +#define PCI_DVSEC_CXL_REG_LOCATOR_BLOCK_ID_MASK __GENMASK(15, 8)
> +#define PCI_DVSEC_CXL_REG_LOCATOR_BLOCK_OFF_LOW_MASK __GENMASK(31, 16)
>
> #endif /* LINUX_PCI_REGS_H */
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 07/25] CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h
2025-09-25 22:34 ` [PATCH v12 07/25] CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h Terry Bowman
2025-09-25 23:53 ` Dave Jiang
@ 2025-10-01 15:58 ` Jonathan Cameron
2025-10-02 15:25 ` Bowman, Terry
1 sibling, 1 reply; 92+ messages in thread
From: Jonathan Cameron @ 2025-10-01 15:58 UTC (permalink / raw)
To: Terry Bowman
Cc: dave, dave.jiang, alison.schofield, dan.j.williams, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, linux-cxl,
alucerop, ira.weiny, linux-kernel, linux-pci
On Thu, 25 Sep 2025 17:34:22 -0500
Terry Bowman <terry.bowman@amd.com> wrote:
> The CXL DVSECs are currently defined in cxl/core/cxlpci.h. These are not
> accessible to other subsystems.
>
> Change DVSEC name formatting to follow the existing PCI format in
> pci_regs.h. The current format uses CXL_DVSEC_XYZ. Change to be PCI_DVSEC_CXL_XYZ.
> Reuse the existing formatting.
>
> Update existing occurrences to match the name change.
>
> Update the inline documentation to refer to latest CXL spec version.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Maybe we discussed it in earlier versions and I've forgotten but generally renaming
uapi defines is a non starter.
I was kind of assuming lspci used these, but nope, it uses hard coded
value of 3 and it's own defines for the fields. (A younger me even reviewed
the patch adding those :) )
https://github.com/pciutils/pciutils/blob/master/ls-ecaps.c#L1279
However, that doesn't mean other code isn't already using those defines.
Minimum I think would be to state here why you think we can get away with
this change.
Personally I'd just not bother changing that one.
Jonathan
> diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
> index f5b17745de60..bd03799612d3 100644
> --- a/include/uapi/linux/pci_regs.h
> +++ b/include/uapi/linux/pci_regs.h
> @@ -1234,9 +1234,64 @@
> /* Deprecated old name, replaced with PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE */
> #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE
>
> -/* Compute Express Link (CXL r3.1, sec 8.1.5) */
> -#define PCI_DVSEC_CXL_PORT 3
This is a userspace header. We can't rename existing definitions
as we have no idea who is using them. Only option would be to
add a comment making the old ones deprecated and adding new ones alongside.
> -#define PCI_DVSEC_CXL_PORT_CTL 0x0c
> -#define PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR 0x00000001
....
> +/* CXL 3.2 8.1.5: Extensions DVSEC for Ports */
> +#define PCI_DVSEC_CXL_PORT_EXT 3
> +#define PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET 0x0c
> +#define PCI_DVSEC_CXL_PORT_EXT_CTL_UNMASK_SBR 0x00000001
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 07/25] CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h
2025-10-01 15:58 ` Jonathan Cameron
@ 2025-10-02 15:25 ` Bowman, Terry
2025-10-03 20:11 ` Cheatham, Benjamin
0 siblings, 1 reply; 92+ messages in thread
From: Bowman, Terry @ 2025-10-02 15:25 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dave, dave.jiang, alison.schofield, dan.j.williams, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, linux-cxl,
alucerop, ira.weiny, linux-kernel, linux-pci
On 10/1/2025 10:58 AM, Jonathan Cameron wrote:
> On Thu, 25 Sep 2025 17:34:22 -0500
> Terry Bowman <terry.bowman@amd.com> wrote:
>
>> The CXL DVSECs are currently defined in cxl/core/cxlpci.h. These are not
>> accessible to other subsystems.
>>
>> Change DVSEC name formatting to follow the existing PCI format in
>> pci_regs.h. The current format uses CXL_DVSEC_XYZ. Change to be PCI_DVSEC_CXL_XYZ.
>> Reuse the existing formatting.
>>
>> Update existing occurrences to match the name change.
>>
>> Update the inline documentation to refer to latest CXL spec version.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Maybe we discussed it in earlier versions and I've forgotten but generally renaming
> uapi defines is a non starter.
>
> I was kind of assuming lspci used these, but nope, it uses hard coded
> value of 3 and it's own defines for the fields. (A younger me even reviewed
> the patch adding those :) )
>
> https://github.com/pciutils/pciutils/blob/master/ls-ecaps.c#L1279
>
> However, that doesn't mean other code isn't already using those defines.
>
> Minimum I think would be to state here why you think we can get away with
> this change.
>
> Personally I'd just not bother changing that one.
>
> Jonathan
>
>
Ok, I'll leave these below as-is.
#define PCI_DVSEC_CXL_PORT 3
#define PCI_DVSEC_CXL_PORT_CTL 0x0c
#define PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR 0x00000001
Terry
>> diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
>> index f5b17745de60..bd03799612d3 100644
>> --- a/include/uapi/linux/pci_regs.h
>> +++ b/include/uapi/linux/pci_regs.h
>> @@ -1234,9 +1234,64 @@
>> /* Deprecated old name, replaced with PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE */
>> #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE
>>
>> -/* Compute Express Link (CXL r3.1, sec 8.1.5) */
>> -#define PCI_DVSEC_CXL_PORT 3
> This is a userspace header. We can't rename existing definitions
> as we have no idea who is using them. Only option would be to
> add a comment making the old ones deprecated and adding new ones alongside.
>
>
>> -#define PCI_DVSEC_CXL_PORT_CTL 0x0c
>> -#define PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR 0x00000001
> ....
>
>> +/* CXL 3.2 8.1.5: Extensions DVSEC for Ports */
>> +#define PCI_DVSEC_CXL_PORT_EXT 3
>> +#define PCI_DVSEC_CXL_PORT_EXT_CTL_OFFSET 0x0c
>> +#define PCI_DVSEC_CXL_PORT_EXT_CTL_UNMASK_SBR 0x00000001
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 07/25] CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h
2025-10-02 15:25 ` Bowman, Terry
@ 2025-10-03 20:11 ` Cheatham, Benjamin
0 siblings, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:11 UTC (permalink / raw)
To: Bowman, Terry, Jonathan Cameron
Cc: dave, dave.jiang, alison.schofield, dan.j.williams, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny,
linux-kernel, linux-pci
On 10/2/2025 10:25 AM, Bowman, Terry wrote:
>
>
> On 10/1/2025 10:58 AM, Jonathan Cameron wrote:
>> On Thu, 25 Sep 2025 17:34:22 -0500
>> Terry Bowman <terry.bowman@amd.com> wrote:
>>
>>> The CXL DVSECs are currently defined in cxl/core/cxlpci.h. These are not
>>> accessible to other subsystems.
>>>
>>> Change DVSEC name formatting to follow the existing PCI format in
>>> pci_regs.h. The current format uses CXL_DVSEC_XYZ. Change to be PCI_DVSEC_CXL_XYZ.
>>> Reuse the existing formatting.
>>>
>>> Update existing occurrences to match the name change.
>>>
>>> Update the inline documentation to refer to latest CXL spec version.
>>>
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> Maybe we discussed it in earlier versions and I've forgotten but generally renaming
>> uapi defines is a non starter.
>>
>> I was kind of assuming lspci used these, but nope, it uses hard coded
>> value of 3 and it's own defines for the fields. (A younger me even reviewed
>> the patch adding those :) )
>>
>> https://github.com/pciutils/pciutils/blob/master/ls-ecaps.c#L1279
>>
>> However, that doesn't mean other code isn't already using those defines.
>>
>> Minimum I think would be to state here why you think we can get away with
>> this change.
>>
>> Personally I'd just not bother changing that one.
>>
>> Jonathan
>>
>>
>
> Ok, I'll leave these below as-is.
>
> #define PCI_DVSEC_CXL_PORT 3
> #define PCI_DVSEC_CXL_PORT_CTL 0x0c
> #define PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR 0x00000001
>
> Terry
>
I think updating to the new names would be better here since they match the other #defines introduced here.
I don't know if this is a no-no, but just re-routing the old ones to the new ones with a comment along the
lines of "Deprecated to match other DVSEC definitions" seems fine to me.
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 08/25] PCI/CXL: Introduce pcie_is_cxl()
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (6 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 07/25] CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-10-03 20:11 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 09/25] PCI/AER: Report CXL or PCIe bus error type in trace logging Terry Bowman
` (16 subsequent siblings)
24 siblings, 1 reply; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
CXL and AER drivers need the ability to identify CXL devices.
Introduce set_pcie_cxl() with logic checking for CXL.mem or CXL.cache
status in the CXL Flexbus DVSEC status register. The CXL Flexbus DVSEC
presence is used because it is required for all the CXL PCIe devices.[1]
Add boolean 'struct pci_dev::is_cxl' with the purpose to cache the CXL
CXL.cache and CXl.mem status.
In the case the device is an EP or USP, call set_pcie_cxl() on behalf of
the parent downstream device. Once a device is created there is
possibilty the parent training or CXL state was updated as well. This
will make certain the correct parent CXL state is cached.
Add function pcie_is_cxl() to return 'struct pci_dev::is_cxl'.
[1] CXL 3.1 Spec, 8.1.1 PCIe Designated Vendor-Specific Extended
Capability (DVSEC) ID Assignment, Table 8-2
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Alejandro Lucero <alucerop@amd.com>
---
Changes in v11->v12:
- Add review-by for Alejandro
- Add comment in set_pcie_cxl() explaining why updating parent status.
Changes in v10->v11:
- Amend set_pcie_cxl() to check for Upstream Port's and EP's parent
downstream port by calling set_pcie_cxl(). (Dan)
- Retitle patch: 'Add' -> 'Introduce'
- Add check for CXL.mem and CXL.cache (Alejandro, Dan)
---
drivers/pci/probe.c | 29 +++++++++++++++++++++++++++++
include/linux/pci.h | 6 ++++++
2 files changed, 35 insertions(+)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index f41128f91ca7..0a9bdf3dd090 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1691,6 +1691,33 @@ static void set_pcie_thunderbolt(struct pci_dev *dev)
dev->is_thunderbolt = 1;
}
+static void set_pcie_cxl(struct pci_dev *dev)
+{
+ struct pci_dev *parent;
+ u16 dvsec = pci_find_dvsec_capability(dev, PCI_VENDOR_ID_CXL,
+ PCI_DVSEC_CXL_FLEXBUS_PORT);
+ if (dvsec) {
+ u16 cap;
+
+ pci_read_config_word(dev, dvsec + PCI_DVSEC_CXL_FLEXBUS_STATUS_OFFSET, &cap);
+
+ dev->is_cxl = FIELD_GET(PCI_DVSEC_CXL_FLEXBUS_STATUS_CACHE_MASK, cap) ||
+ FIELD_GET(PCI_DVSEC_CXL_FLEXBUS_STATUS_MEM_MASK, cap);
+ }
+
+ if (!pci_is_pcie(dev) ||
+ !(pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT ||
+ pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM))
+ return;
+
+ /*
+ * Update parent's CXL state because alternate protocol training
+ * may have changed
+ */
+ parent = pci_upstream_bridge(dev);
+ set_pcie_cxl(parent);
+}
+
static void set_pcie_untrusted(struct pci_dev *dev)
{
struct pci_dev *parent = pci_upstream_bridge(dev);
@@ -2021,6 +2048,8 @@ int pci_setup_device(struct pci_dev *dev)
/* Need to have dev->cfg_size ready */
set_pcie_thunderbolt(dev);
+ set_pcie_cxl(dev);
+
set_pcie_untrusted(dev);
if (pci_is_pcie(dev))
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 59876de13860..53a45e92c635 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -459,6 +459,7 @@ struct pci_dev {
unsigned int is_pciehp:1;
unsigned int shpc_managed:1; /* SHPC owned by shpchp */
unsigned int is_thunderbolt:1; /* Thunderbolt controller */
+ unsigned int is_cxl:1; /* Compute Express Link (CXL) */
/*
* Devices marked being untrusted are the ones that can potentially
* execute DMA attacks and similar. They are typically connected
@@ -765,6 +766,11 @@ static inline bool pci_is_display(struct pci_dev *pdev)
return (pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY;
}
+static inline bool pcie_is_cxl(struct pci_dev *pci_dev)
+{
+ return pci_dev->is_cxl;
+}
+
#define for_each_pci_bridge(dev, bus) \
list_for_each_entry(dev, &bus->devices, bus_list) \
if (!pci_is_bridge(dev)) {} else
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 08/25] PCI/CXL: Introduce pcie_is_cxl()
2025-09-25 22:34 ` [PATCH v12 08/25] PCI/CXL: Introduce pcie_is_cxl() Terry Bowman
@ 2025-10-03 20:11 ` Cheatham, Benjamin
0 siblings, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:11 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-pci, dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
[snip]
>
> +static void set_pcie_cxl(struct pci_dev *dev)
> +{
> + struct pci_dev *parent;
> + u16 dvsec = pci_find_dvsec_capability(dev, PCI_VENDOR_ID_CXL,
> + PCI_DVSEC_CXL_FLEXBUS_PORT);
> + if (dvsec) {
> + u16 cap;
> +
> + pci_read_config_word(dev, dvsec + PCI_DVSEC_CXL_FLEXBUS_STATUS_OFFSET, &cap);
> +
> + dev->is_cxl = FIELD_GET(PCI_DVSEC_CXL_FLEXBUS_STATUS_CACHE_MASK, cap) ||
> + FIELD_GET(PCI_DVSEC_CXL_FLEXBUS_STATUS_MEM_MASK, cap);
> + }
> +
> + if (!pci_is_pcie(dev) ||
Really small optimization nit, but you can move this check to before you look for the dvsec and
return early if it's true. It shouldn't be possible for a non-PCIe device to have CXL capabilities.
Either way:
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 09/25] PCI/AER: Report CXL or PCIe bus error type in trace logging
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (7 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 08/25] PCI/CXL: Introduce pcie_is_cxl() Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-10-03 20:11 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 10/25] CXL/AER: Update PCI class code check to use FIELD_GET() Terry Bowman
` (15 subsequent siblings)
24 siblings, 1 reply; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
The AER service driver and aer_event tracing currently log 'PCIe Bus Type'
for all errors. Update the driver and aer_event tracing to log 'CXL Bus
Type' for CXL device errors.
This requires the AER can identify and distinguish between PCIe errors and
CXL errors.
Introduce boolean 'is_cxl' to 'struct aer_err_info'. Add assignment in
aer_get_device_error_info() and pci_print_aer().
Update the aer_event trace routine to accept a bus type string parameter.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
---
Changes in v11->v12:
- Change aer_err_info::is_cxl to be bool a bitfield. Update structure
padding. (Lukas)
- Add kernel-doc for 'struct aer_err_info' (Lukas)
Changes in v10->v11:
- Remove duplicate call to trace_aer_event() (Shiju)
- Added Dan William's and Dave Jiang's reviewed-by
---
drivers/pci/pci.h | 25 ++++++++++++++++++++++++-
drivers/pci/pcie/aer.c | 18 ++++++++++++------
include/ras/ras_event.h | 9 ++++++---
3 files changed, 42 insertions(+), 10 deletions(-)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 0c7178d0ef9d..f7631f40e57c 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -607,6 +607,23 @@ static inline bool pci_dev_binding_disallowed(struct pci_dev *dev)
#define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */
+/**
+ * struct aer_err_info - AER Error Information
+ * @dev: Devices reporting error
+ * @ratelimit_print: Flag to log or not log the devices' error. 0=NotLog/1=Log
+ * @error_devnum: Number of devices reporting an error
+ * @level: printk level to use in logging
+ * @id: Value from register PCI_ERR_ROOT_ERR_SRC
+ * @severity: AER severity, 0-UNCOR Non-fatal, 1-UNCOR fatal, 2-COR
+ * @root_ratelimit_print: Flag to log or not log the root's error. 0=NotLog/1=Log
+ * @multi_error_valid: If multiple errors are reported
+ * @first_error: First reported error
+ * @is_cxl: Bus type error: 0-PCI Bus error, 1-CXL Bus error
+ * @tlp_header_valid: Indicates if TLP field contains error information
+ * @status: COR/UNCOR error status
+ * @mask: COR/UNCOR mask
+ * @tlp: Transaction packet information
+ */
struct aer_err_info {
struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
int ratelimit_print[AER_MAX_MULTI_ERR_DEVICES];
@@ -621,7 +638,8 @@ struct aer_err_info {
unsigned int multi_error_valid:1;
unsigned int first_error:5;
- unsigned int __pad2:2;
+ unsigned int __pad2:1;
+ bool is_cxl:1; /* CXL or PCI bus error? */
unsigned int tlp_header_valid:1;
unsigned int status; /* COR/UNCOR Error Status */
@@ -632,6 +650,11 @@ struct aer_err_info {
int aer_get_device_error_info(struct aer_err_info *info, int i);
void aer_print_error(struct aer_err_info *info, int i);
+static inline const char *aer_err_bus(struct aer_err_info *info)
+{
+ return info->is_cxl ? "CXL" : "PCIe";
+}
+
int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2,
unsigned int tlp_len, bool flit,
struct pcie_tlp_log *log);
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 6e5c9efe2920..befa73ace9bb 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -837,6 +837,7 @@ void aer_print_error(struct aer_err_info *info, int i)
struct pci_dev *dev;
int layer, agent, id;
const char *level = info->level;
+ const char *bus_type = aer_err_bus(info);
if (WARN_ON_ONCE(i >= AER_MAX_MULTI_ERR_DEVICES))
return;
@@ -845,23 +846,23 @@ void aer_print_error(struct aer_err_info *info, int i)
id = pci_dev_id(dev);
pci_dev_aer_stats_incr(dev, info);
- trace_aer_event(pci_name(dev), (info->status & ~info->mask),
+ trace_aer_event(pci_name(dev), bus_type, (info->status & ~info->mask),
info->severity, info->tlp_header_valid, &info->tlp);
if (!info->ratelimit_print[i])
return;
if (!info->status) {
- pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
- aer_error_severity_string[info->severity]);
+ pci_err(dev, "%s Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
+ bus_type, aer_error_severity_string[info->severity]);
goto out;
}
layer = AER_GET_LAYER_ERROR(info->severity, info->status);
agent = AER_GET_AGENT(info->severity, info->status);
- aer_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
- aer_error_severity_string[info->severity],
+ aer_printk(level, dev, "%s Bus Error: severity=%s, type=%s, (%s)\n",
+ bus_type, aer_error_severity_string[info->severity],
aer_error_layer[layer], aer_agent_string[agent]);
aer_printk(level, dev, " device [%04x:%04x] error status/mask=%08x/%08x\n",
@@ -895,6 +896,7 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer);
void pci_print_aer(struct pci_dev *dev, int aer_severity,
struct aer_capability_regs *aer)
{
+ const char *bus_type;
int layer, agent, tlp_header_valid = 0;
u32 status, mask;
struct aer_err_info info = {
@@ -915,9 +917,12 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
info.status = status;
info.mask = mask;
+ info.is_cxl = pcie_is_cxl(dev);
+
+ bus_type = aer_err_bus(&info);
pci_dev_aer_stats_incr(dev, &info);
- trace_aer_event(pci_name(dev), (status & ~mask),
+ trace_aer_event(pci_name(dev), bus_type, (status & ~mask),
aer_severity, tlp_header_valid, &aer->header_log);
if (!aer_ratelimit(dev, info.severity))
@@ -1278,6 +1283,7 @@ int aer_get_device_error_info(struct aer_err_info *info, int i)
/* Must reset in this function */
info->status = 0;
info->tlp_header_valid = 0;
+ info->is_cxl = pcie_is_cxl(dev);
/* The device might not support AER */
if (!aer)
diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
index c8cd0f00c845..85dbafec6ad1 100644
--- a/include/ras/ras_event.h
+++ b/include/ras/ras_event.h
@@ -298,15 +298,17 @@ TRACE_EVENT(non_standard_event,
TRACE_EVENT(aer_event,
TP_PROTO(const char *dev_name,
+ const char *bus_type,
const u32 status,
const u8 severity,
const u8 tlp_header_valid,
struct pcie_tlp_log *tlp),
- TP_ARGS(dev_name, status, severity, tlp_header_valid, tlp),
+ TP_ARGS(dev_name, bus_type, status, severity, tlp_header_valid, tlp),
TP_STRUCT__entry(
__string( dev_name, dev_name )
+ __string( bus_type, bus_type )
__field( u32, status )
__field( u8, severity )
__field( u8, tlp_header_valid)
@@ -315,6 +317,7 @@ TRACE_EVENT(aer_event,
TP_fast_assign(
__assign_str(dev_name);
+ __assign_str(bus_type);
__entry->status = status;
__entry->severity = severity;
__entry->tlp_header_valid = tlp_header_valid;
@@ -326,8 +329,8 @@ TRACE_EVENT(aer_event,
}
),
- TP_printk("%s PCIe Bus Error: severity=%s, %s, TLP Header=%s\n",
- __get_str(dev_name),
+ TP_printk("%s %s Bus Error: severity=%s, %s, TLP Header=%s\n",
+ __get_str(dev_name), __get_str(bus_type),
__entry->severity == AER_CORRECTABLE ? "Corrected" :
__entry->severity == AER_FATAL ?
"Fatal" : "Uncorrected, non-fatal",
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 09/25] PCI/AER: Report CXL or PCIe bus error type in trace logging
2025-09-25 22:34 ` [PATCH v12 09/25] PCI/AER: Report CXL or PCIe bus error type in trace logging Terry Bowman
@ 2025-10-03 20:11 ` Cheatham, Benjamin
2025-10-06 19:59 ` Bowman, Terry
0 siblings, 1 reply; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:11 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
[snip]
> +/**
> + * struct aer_err_info - AER Error Information
> + * @dev: Devices reporting error
> + * @ratelimit_print: Flag to log or not log the devices' error. 0=NotLog/1=Log
> + * @error_devnum: Number of devices reporting an error
> + * @level: printk level to use in logging
> + * @id: Value from register PCI_ERR_ROOT_ERR_SRC
> + * @severity: AER severity, 0-UNCOR Non-fatal, 1-UNCOR fatal, 2-COR
> + * @root_ratelimit_print: Flag to log or not log the root's error. 0=NotLog/1=Log
> + * @multi_error_valid: If multiple errors are reported
> + * @first_error: First reported error
> + * @is_cxl: Bus type error: 0-PCI Bus error, 1-CXL Bus error
> + * @tlp_header_valid: Indicates if TLP field contains error information
> + * @status: COR/UNCOR error status
> + * @mask: COR/UNCOR mask
> + * @tlp: Transaction packet information
> + */
> struct aer_err_info {
> struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
> int ratelimit_print[AER_MAX_MULTI_ERR_DEVICES];
> @@ -621,7 +638,8 @@ struct aer_err_info {
> unsigned int multi_error_valid:1;
>
> unsigned int first_error:5;
> - unsigned int __pad2:2;
> + unsigned int __pad2:1;
> + bool is_cxl:1; /* CXL or PCI bus error? */
> unsigned int tlp_header_valid:1;
>
> unsigned int status; /* COR/UNCOR Error Status */
I'd get rid of the comments after the members since it's the exact same thing as the kernel
doc above the struct.
> @@ -632,6 +650,11 @@ struct aer_err_info {
> int aer_get_device_error_info(struct aer_err_info *info, int i);
> void aer_print_error(struct aer_err_info *info, int i);
>
> +static inline const char *aer_err_bus(struct aer_err_info *info)
> +{
> + return info->is_cxl ? "CXL" : "PCIe";
> +}
> +
> int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2,
> unsigned int tlp_len, bool flit,
> struct pcie_tlp_log *log);
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index 6e5c9efe2920..befa73ace9bb 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -837,6 +837,7 @@ void aer_print_error(struct aer_err_info *info, int i)
> struct pci_dev *dev;
> int layer, agent, id;
> const char *level = info->level;
> + const char *bus_type = aer_err_bus(info);
>
> if (WARN_ON_ONCE(i >= AER_MAX_MULTI_ERR_DEVICES))
> return;
> @@ -845,23 +846,23 @@ void aer_print_error(struct aer_err_info *info, int i)
> id = pci_dev_id(dev);
>
> pci_dev_aer_stats_incr(dev, info);
> - trace_aer_event(pci_name(dev), (info->status & ~info->mask),
> + trace_aer_event(pci_name(dev), bus_type, (info->status & ~info->mask),
> info->severity, info->tlp_header_valid, &info->tlp);
>
> if (!info->ratelimit_print[i])
> return;
>
> if (!info->status) {
> - pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
> - aer_error_severity_string[info->severity]);
> + pci_err(dev, "%s Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
> + bus_type, aer_error_severity_string[info->severity]);
> goto out;
> }
>
> layer = AER_GET_LAYER_ERROR(info->severity, info->status);
> agent = AER_GET_AGENT(info->severity, info->status);
>
> - aer_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
> - aer_error_severity_string[info->severity],
> + aer_printk(level, dev, "%s Bus Error: severity=%s, type=%s, (%s)\n",
> + bus_type, aer_error_severity_string[info->severity],
> aer_error_layer[layer], aer_agent_string[agent]);
>
> aer_printk(level, dev, " device [%04x:%04x] error status/mask=%08x/%08x\n",
> @@ -895,6 +896,7 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer);
> void pci_print_aer(struct pci_dev *dev, int aer_severity,
> struct aer_capability_regs *aer)
> {
> + const char *bus_type;
> int layer, agent, tlp_header_valid = 0;
> u32 status, mask;
> struct aer_err_info info = {
> @@ -915,9 +917,12 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>
> info.status = status;
> info.mask = mask;
> + info.is_cxl = pcie_is_cxl(dev);
> +
> + bus_type = aer_err_bus(&info);
>
> pci_dev_aer_stats_incr(dev, &info);
> - trace_aer_event(pci_name(dev), (status & ~mask),
> + trace_aer_event(pci_name(dev), bus_type, (status & ~mask),
> aer_severity, tlp_header_valid, &aer->header_log);
>
> if (!aer_ratelimit(dev, info.severity))
> @@ -1278,6 +1283,7 @@ int aer_get_device_error_info(struct aer_err_info *info, int i)
> /* Must reset in this function */
> info->status = 0;
> info->tlp_header_valid = 0;
> + info->is_cxl = pcie_is_cxl(dev);
>
So am I right in assuming every AER error that occurs while the link is trained
as a CXL link will be reported as a CXL error? Sorry if this is a stupid question,
but is it possible for a PCIe error to occur or does CXL.io just replace the PCIe
protocol once the link is trained as CXL?
If so, do we not care if the error is a PCIe-level error and just report it as
a CXL error anyway?
Sorry if you've already hashed all of this out, but I figured I'd ask just to make sure.
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 09/25] PCI/AER: Report CXL or PCIe bus error type in trace logging
2025-10-03 20:11 ` Cheatham, Benjamin
@ 2025-10-06 19:59 ` Bowman, Terry
0 siblings, 0 replies; 92+ messages in thread
From: Bowman, Terry @ 2025-10-06 19:59 UTC (permalink / raw)
To: Cheatham, Benjamin
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 10/3/2025 3:11 PM, Cheatham, Benjamin wrote:
> [snip]
>
>> +/**
>> + * struct aer_err_info - AER Error Information
>> + * @dev: Devices reporting error
>> + * @ratelimit_print: Flag to log or not log the devices' error. 0=NotLog/1=Log
>> + * @error_devnum: Number of devices reporting an error
>> + * @level: printk level to use in logging
>> + * @id: Value from register PCI_ERR_ROOT_ERR_SRC
>> + * @severity: AER severity, 0-UNCOR Non-fatal, 1-UNCOR fatal, 2-COR
>> + * @root_ratelimit_print: Flag to log or not log the root's error. 0=NotLog/1=Log
>> + * @multi_error_valid: If multiple errors are reported
>> + * @first_error: First reported error
>> + * @is_cxl: Bus type error: 0-PCI Bus error, 1-CXL Bus error
>> + * @tlp_header_valid: Indicates if TLP field contains error information
>> + * @status: COR/UNCOR error status
>> + * @mask: COR/UNCOR mask
>> + * @tlp: Transaction packet information
>> + */
>> struct aer_err_info {
>> struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
>> int ratelimit_print[AER_MAX_MULTI_ERR_DEVICES];
>> @@ -621,7 +638,8 @@ struct aer_err_info {
>> unsigned int multi_error_valid:1;
>>
>> unsigned int first_error:5;
>> - unsigned int __pad2:2;
>> + unsigned int __pad2:1;
>> + bool is_cxl:1; /* CXL or PCI bus error? */
>> unsigned int tlp_header_valid:1;
>>
>> unsigned int status; /* COR/UNCOR Error Status */
> I'd get rid of the comments after the members since it's the exact same thing as the kernel
> doc above the struct.
Good idea.
>> @@ -632,6 +650,11 @@ struct aer_err_info {
>> int aer_get_device_error_info(struct aer_err_info *info, int i);
>> void aer_print_error(struct aer_err_info *info, int i);
>>
>> +static inline const char *aer_err_bus(struct aer_err_info *info)
>> +{
>> + return info->is_cxl ? "CXL" : "PCIe";
>> +}
>> +
>> int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2,
>> unsigned int tlp_len, bool flit,
>> struct pcie_tlp_log *log);
>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>> index 6e5c9efe2920..befa73ace9bb 100644
>> --- a/drivers/pci/pcie/aer.c
>> +++ b/drivers/pci/pcie/aer.c
>> @@ -837,6 +837,7 @@ void aer_print_error(struct aer_err_info *info, int i)
>> struct pci_dev *dev;
>> int layer, agent, id;
>> const char *level = info->level;
>> + const char *bus_type = aer_err_bus(info);
>>
>> if (WARN_ON_ONCE(i >= AER_MAX_MULTI_ERR_DEVICES))
>> return;
>> @@ -845,23 +846,23 @@ void aer_print_error(struct aer_err_info *info, int i)
>> id = pci_dev_id(dev);
>>
>> pci_dev_aer_stats_incr(dev, info);
>> - trace_aer_event(pci_name(dev), (info->status & ~info->mask),
>> + trace_aer_event(pci_name(dev), bus_type, (info->status & ~info->mask),
>> info->severity, info->tlp_header_valid, &info->tlp);
>>
>> if (!info->ratelimit_print[i])
>> return;
>>
>> if (!info->status) {
>> - pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
>> - aer_error_severity_string[info->severity]);
>> + pci_err(dev, "%s Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
>> + bus_type, aer_error_severity_string[info->severity]);
>> goto out;
>> }
>>
>> layer = AER_GET_LAYER_ERROR(info->severity, info->status);
>> agent = AER_GET_AGENT(info->severity, info->status);
>>
>> - aer_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
>> - aer_error_severity_string[info->severity],
>> + aer_printk(level, dev, "%s Bus Error: severity=%s, type=%s, (%s)\n",
>> + bus_type, aer_error_severity_string[info->severity],
>> aer_error_layer[layer], aer_agent_string[agent]);
>>
>> aer_printk(level, dev, " device [%04x:%04x] error status/mask=%08x/%08x\n",
>> @@ -895,6 +896,7 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer);
>> void pci_print_aer(struct pci_dev *dev, int aer_severity,
>> struct aer_capability_regs *aer)
>> {
>> + const char *bus_type;
>> int layer, agent, tlp_header_valid = 0;
>> u32 status, mask;
>> struct aer_err_info info = {
>> @@ -915,9 +917,12 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>>
>> info.status = status;
>> info.mask = mask;
>> + info.is_cxl = pcie_is_cxl(dev);
>> +
>> + bus_type = aer_err_bus(&info);
>>
>> pci_dev_aer_stats_incr(dev, &info);
>> - trace_aer_event(pci_name(dev), (status & ~mask),
>> + trace_aer_event(pci_name(dev), bus_type, (status & ~mask),
>> aer_severity, tlp_header_valid, &aer->header_log);
>>
>> if (!aer_ratelimit(dev, info.severity))
>> @@ -1278,6 +1283,7 @@ int aer_get_device_error_info(struct aer_err_info *info, int i)
>> /* Must reset in this function */
>> info->status = 0;
>> info->tlp_header_valid = 0;
>> + info->is_cxl = pcie_is_cxl(dev);
>>
> So am I right in assuming every AER error that occurs while the link is trained
> as a CXL link will be reported as a CXL error? Sorry if this is a stupid question,
> but is it possible for a PCIe error to occur or does CXL.io just replace the PCIe
> protocol once the link is trained as CXL?
Correct. Any PCI bus protocol errors reported while CXL trained will be reported as
CXL errors.
In your example a "PCIe error" will be detected as a CXL.io error and the AER driver
will log the extended AER register status. The device's CXL RAS will also be logged
if it is a CXL bus error.
> If so, do we not care if the error is a PCIe-level error and just report it as
> a CXL error anyway?
We can't access CXL RAS if its not a CXL error and not a device.
> Sorry if you've already hashed all of this out, but I figured I'd ask just to make sure.
Terry
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 10/25] CXL/AER: Update PCI class code check to use FIELD_GET()
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (8 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 09/25] PCI/AER: Report CXL or PCIe bus error type in trace logging Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-26 0:02 ` Dave Jiang
2025-10-01 16:12 ` Jonathan Cameron
2025-09-25 22:34 ` [PATCH v12 11/25] cxl/pci: Update RAS handler interfaces to also support CXL Ports Terry Bowman
` (14 subsequent siblings)
24 siblings, 2 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
Update the AER driver's is_cxl_mem_dev() to use FIELD_GET() while checking
for a CXL Endpoint class code.
Introduce a genmask bitmask for checking PCI class codes and locate in
include/uapi/linux/pci_regs.h.
Update the function documentation to reference the latest CXL
specification.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
Changes in v11->v12:
Changes in v10->v11:
- Add #include <linux/bitfield.h> to cxl_ras.c
- Removed line wrapping at "(CXL 3.2, 8.1.12.1)".
---
drivers/pci/pcie/aer.c | 1 +
drivers/pci/pcie/aer_cxl_rch.c | 6 +++---
include/uapi/linux/pci_regs.h | 2 ++
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index befa73ace9bb..6ba8f84add70 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -30,6 +30,7 @@
#include <linux/kfifo.h>
#include <linux/ratelimit.h>
#include <linux/slab.h>
+#include <linux/bitfield.h>
#include <acpi/apei.h>
#include <acpi/ghes.h>
#include <ras/ras_event.h>
diff --git a/drivers/pci/pcie/aer_cxl_rch.c b/drivers/pci/pcie/aer_cxl_rch.c
index bfe071eebf67..c3e2d4cbe8cc 100644
--- a/drivers/pci/pcie/aer_cxl_rch.c
+++ b/drivers/pci/pcie/aer_cxl_rch.c
@@ -17,10 +17,10 @@ static bool is_cxl_mem_dev(struct pci_dev *dev)
return false;
/*
- * CXL Memory Devices must have the 502h class code set (CXL
- * 3.0, 8.1.12.1).
+ * CXL Memory Devices must have the 502h class code set
+ * (CXL 3.2, 8.1.12.1).
*/
- if ((dev->class >> 8) != PCI_CLASS_MEMORY_CXL)
+ if (FIELD_GET(PCI_CLASS_CODE_MASK, dev->class) != PCI_CLASS_MEMORY_CXL)
return false;
return true;
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index bd03799612d3..802a7384f99a 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -73,6 +73,8 @@
#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
#define PCI_CLASS_DEVICE 0x0a /* Device class */
+#define PCI_CLASS_CODE_MASK __GENMASK(23, 8)
+
#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
#define PCI_HEADER_TYPE 0x0e /* 8 bits */
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 10/25] CXL/AER: Update PCI class code check to use FIELD_GET()
2025-09-25 22:34 ` [PATCH v12 10/25] CXL/AER: Update PCI class code check to use FIELD_GET() Terry Bowman
@ 2025-09-26 0:02 ` Dave Jiang
2025-10-01 16:12 ` Jonathan Cameron
1 sibling, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-26 0:02 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> Update the AER driver's is_cxl_mem_dev() to use FIELD_GET() while checking
> for a CXL Endpoint class code.
>
> Introduce a genmask bitmask for checking PCI class codes and locate in
> include/uapi/linux/pci_regs.h.
>
> Update the function documentation to reference the latest CXL
> specification.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> ---
>
> Changes in v11->v12:
>
> Changes in v10->v11:
> - Add #include <linux/bitfield.h> to cxl_ras.c
> - Removed line wrapping at "(CXL 3.2, 8.1.12.1)".
> ---
> drivers/pci/pcie/aer.c | 1 +
> drivers/pci/pcie/aer_cxl_rch.c | 6 +++---
> include/uapi/linux/pci_regs.h | 2 ++
> 3 files changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index befa73ace9bb..6ba8f84add70 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -30,6 +30,7 @@
> #include <linux/kfifo.h>
> #include <linux/ratelimit.h>
> #include <linux/slab.h>
> +#include <linux/bitfield.h>
> #include <acpi/apei.h>
> #include <acpi/ghes.h>
> #include <ras/ras_event.h>
> diff --git a/drivers/pci/pcie/aer_cxl_rch.c b/drivers/pci/pcie/aer_cxl_rch.c
> index bfe071eebf67..c3e2d4cbe8cc 100644
> --- a/drivers/pci/pcie/aer_cxl_rch.c
> +++ b/drivers/pci/pcie/aer_cxl_rch.c
> @@ -17,10 +17,10 @@ static bool is_cxl_mem_dev(struct pci_dev *dev)
> return false;
>
> /*
> - * CXL Memory Devices must have the 502h class code set (CXL
> - * 3.0, 8.1.12.1).
> + * CXL Memory Devices must have the 502h class code set
> + * (CXL 3.2, 8.1.12.1).
> */
> - if ((dev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> + if (FIELD_GET(PCI_CLASS_CODE_MASK, dev->class) != PCI_CLASS_MEMORY_CXL)
> return false;
>
> return true;
> diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
> index bd03799612d3..802a7384f99a 100644
> --- a/include/uapi/linux/pci_regs.h
> +++ b/include/uapi/linux/pci_regs.h
> @@ -73,6 +73,8 @@
> #define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
> #define PCI_CLASS_DEVICE 0x0a /* Device class */
>
> +#define PCI_CLASS_CODE_MASK __GENMASK(23, 8)
> +
> #define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
> #define PCI_LATENCY_TIMER 0x0d /* 8 bits */
> #define PCI_HEADER_TYPE 0x0e /* 8 bits */
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 10/25] CXL/AER: Update PCI class code check to use FIELD_GET()
2025-09-25 22:34 ` [PATCH v12 10/25] CXL/AER: Update PCI class code check to use FIELD_GET() Terry Bowman
2025-09-26 0:02 ` Dave Jiang
@ 2025-10-01 16:12 ` Jonathan Cameron
2025-10-02 7:40 ` Lukas Wunner
1 sibling, 1 reply; 92+ messages in thread
From: Jonathan Cameron @ 2025-10-01 16:12 UTC (permalink / raw)
To: Terry Bowman
Cc: dave, dave.jiang, alison.schofield, dan.j.williams, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, linux-cxl,
alucerop, ira.weiny, linux-kernel, linux-pci
On Thu, 25 Sep 2025 17:34:25 -0500
Terry Bowman <terry.bowman@amd.com> wrote:
> Update the AER driver's is_cxl_mem_dev() to use FIELD_GET() while checking
> for a CXL Endpoint class code.
>
> Introduce a genmask bitmask for checking PCI class codes and locate in
> include/uapi/linux/pci_regs.h.
>
> Update the function documentation to reference the latest CXL
> specification.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>
The way that class code definitions work in pci_ids.h is somewhat odd
in my opinion, so I'd like input from Bjorn, Lukas etc on whether a
generic mask definition is a good idea or more likely to cause problems.
See for example.
#define PCI_BASE_CLASS_STORAGE 0x01
...
#define PCI_CLASS_STORAGE_SATA 0x0106
#define PCI_CLASS_STORAGE_SATA_AHCI 0x010601
This variability in what is called CLASS_* leads to fun
situations like in drivers/ata/ahci.c where we have some
PCI_CLASS_* shifted and some not...
> ---
>
> Changes in v11->v12:
>
> Changes in v10->v11:
> - Add #include <linux/bitfield.h> to cxl_ras.c
> - Removed line wrapping at "(CXL 3.2, 8.1.12.1)".
> ---
> drivers/pci/pcie/aer.c | 1 +
> drivers/pci/pcie/aer_cxl_rch.c | 6 +++---
> include/uapi/linux/pci_regs.h | 2 ++
> 3 files changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index befa73ace9bb..6ba8f84add70 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -30,6 +30,7 @@
> #include <linux/kfifo.h>
> #include <linux/ratelimit.h>
> #include <linux/slab.h>
> +#include <linux/bitfield.h>
> #include <acpi/apei.h>
> #include <acpi/ghes.h>
> #include <ras/ras_event.h>
> diff --git a/drivers/pci/pcie/aer_cxl_rch.c b/drivers/pci/pcie/aer_cxl_rch.c
> index bfe071eebf67..c3e2d4cbe8cc 100644
> --- a/drivers/pci/pcie/aer_cxl_rch.c
> +++ b/drivers/pci/pcie/aer_cxl_rch.c
> @@ -17,10 +17,10 @@ static bool is_cxl_mem_dev(struct pci_dev *dev)
> return false;
>
> /*
> - * CXL Memory Devices must have the 502h class code set (CXL
> - * 3.0, 8.1.12.1).
> + * CXL Memory Devices must have the 502h class code set
> + * (CXL 3.2, 8.1.12.1).
> */
> - if ((dev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> + if (FIELD_GET(PCI_CLASS_CODE_MASK, dev->class) != PCI_CLASS_MEMORY_CXL)
> return false;
>
> return true;
> diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
> index bd03799612d3..802a7384f99a 100644
> --- a/include/uapi/linux/pci_regs.h
> +++ b/include/uapi/linux/pci_regs.h
> @@ -73,6 +73,8 @@
> #define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
> #define PCI_CLASS_DEVICE 0x0a /* Device class */
>
> +#define PCI_CLASS_CODE_MASK __GENMASK(23, 8)
> +
> #define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
> #define PCI_LATENCY_TIMER 0x0d /* 8 bits */
> #define PCI_HEADER_TYPE 0x0e /* 8 bits */
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 10/25] CXL/AER: Update PCI class code check to use FIELD_GET()
2025-10-01 16:12 ` Jonathan Cameron
@ 2025-10-02 7:40 ` Lukas Wunner
2025-10-30 17:16 ` Bowman, Terry
0 siblings, 1 reply; 92+ messages in thread
From: Lukas Wunner @ 2025-10-02 7:40 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Terry Bowman, dave, dave.jiang, alison.schofield, dan.j.williams,
bhelgaas, shiju.jose, ming.li, Smita.KoralahalliChannabasappa,
rrichter, dan.carpenter, PradeepVineshReddy.Kodamati,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, linux-cxl,
alucerop, ira.weiny, linux-kernel, linux-pci
On Wed, Oct 01, 2025 at 05:12:16PM +0100, Jonathan Cameron wrote:
> On Thu, 25 Sep 2025 17:34:25 -0500 Terry Bowman <terry.bowman@amd.com> wrote:
> The way that class code definitions work in pci_ids.h is somewhat odd
> in my opinion, so I'd like input from Bjorn, Lukas etc on whether a
> generic mask definition is a good idea or more likely to cause problems.
>
> See for example.
> #define PCI_BASE_CLASS_STORAGE 0x01
> ...
>
> #define PCI_CLASS_STORAGE_SATA 0x0106
> #define PCI_CLASS_STORAGE_SATA_AHCI 0x010601
>
> This variability in what is called CLASS_* leads to fun
> situations like in drivers/ata/ahci.c where we have some
> PCI_CLASS_* shifted and some not...
Macros working with PCI class codes generally accept a "shift" parameter
to know by how many bits the class code needs to be shifted, see e.g.
DECLARE_PCI_FIXUP_CLASS_EARLY() and friends.
A macro which shifts exactly by 8 is hence only of limited use.
> > +++ b/drivers/pci/pcie/aer_cxl_rch.c
> > @@ -17,10 +17,10 @@ static bool is_cxl_mem_dev(struct pci_dev *dev)
> > return false;
> >
> > /*
> > - * CXL Memory Devices must have the 502h class code set (CXL
> > - * 3.0, 8.1.12.1).
> > + * CXL Memory Devices must have the 502h class code set
> > + * (CXL 3.2, 8.1.12.1).
> > */
> > - if ((dev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> > + if (FIELD_GET(PCI_CLASS_CODE_MASK, dev->class) != PCI_CLASS_MEMORY_CXL)
> > return false;
Hm, this doesn't look more readable TBH.
Refactoring changes like this one should be submitted separately from
this patch set. If any of them are controversial, they delay upstreaming
of the actual change, i.e. the CXL AER plumbing. They also increase the
size of the patch set, making it more difficult to review.
> > +++ b/include/uapi/linux/pci_regs.h
> > @@ -73,6 +73,8 @@
> > #define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
> > #define PCI_CLASS_DEVICE 0x0a /* Device class */
> >
> > +#define PCI_CLASS_CODE_MASK __GENMASK(23, 8)
> > +
> > #define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
> > #define PCI_LATENCY_TIMER 0x0d /* 8 bits */
> > #define PCI_HEADER_TYPE 0x0e /* 8 bits */
Putting this in a uapi header means we'll have to support it
indefinitely. Usually such macros are added to kernel-internal
headers first and moved to uapi headers if/when the need arises.
Thanks,
Lukas
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 10/25] CXL/AER: Update PCI class code check to use FIELD_GET()
2025-10-02 7:40 ` Lukas Wunner
@ 2025-10-30 17:16 ` Bowman, Terry
2025-10-31 5:30 ` Lukas Wunner
0 siblings, 1 reply; 92+ messages in thread
From: Bowman, Terry @ 2025-10-30 17:16 UTC (permalink / raw)
To: Lukas Wunner, Jonathan Cameron
Cc: dave, dave.jiang, alison.schofield, dan.j.williams, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny,
linux-kernel, linux-pci
On 10/2/2025 2:40 AM, Lukas Wunner wrote:
> On Wed, Oct 01, 2025 at 05:12:16PM +0100, Jonathan Cameron wrote:
>> On Thu, 25 Sep 2025 17:34:25 -0500 Terry Bowman <terry.bowman@amd.com> wrote:
>> The way that class code definitions work in pci_ids.h is somewhat odd
>> in my opinion, so I'd like input from Bjorn, Lukas etc on whether a
>> generic mask definition is a good idea or more likely to cause problems.
>>
>> See for example.
>> #define PCI_BASE_CLASS_STORAGE 0x01
>> ...
>>
>> #define PCI_CLASS_STORAGE_SATA 0x0106
>> #define PCI_CLASS_STORAGE_SATA_AHCI 0x010601
>>
>> This variability in what is called CLASS_* leads to fun
>> situations like in drivers/ata/ahci.c where we have some
>> PCI_CLASS_* shifted and some not...
> Macros working with PCI class codes generally accept a "shift" parameter
> to know by how many bits the class code needs to be shifted, see e.g.
> DECLARE_PCI_FIXUP_CLASS_EARLY() and friends.
>
> A macro which shifts exactly by 8 is hence only of limited use.
>
>
>>> +++ b/drivers/pci/pcie/aer_cxl_rch.c
>>> @@ -17,10 +17,10 @@ static bool is_cxl_mem_dev(struct pci_dev *dev)
>>> return false;
>>>
>>> /*
>>> - * CXL Memory Devices must have the 502h class code set (CXL
>>> - * 3.0, 8.1.12.1).
>>> + * CXL Memory Devices must have the 502h class code set
>>> + * (CXL 3.2, 8.1.12.1).
>>> */
>>> - if ((dev->class >> 8) != PCI_CLASS_MEMORY_CXL)
>>> + if (FIELD_GET(PCI_CLASS_CODE_MASK, dev->class) != PCI_CLASS_MEMORY_CXL)
>>> return false;
> Hm, this doesn't look more readable TBH.
>
> Refactoring changes like this one should be submitted separately from
> this patch set. If any of them are controversial, they delay upstreaming
> of the actual change, i.e. the CXL AER plumbing. They also increase the
> size of the patch set, making it more difficult to review.
>
>
>>> +++ b/include/uapi/linux/pci_regs.h
>>> @@ -73,6 +73,8 @@
>>> #define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
>>> #define PCI_CLASS_DEVICE 0x0a /* Device class */
>>>
>>> +#define PCI_CLASS_CODE_MASK __GENMASK(23, 8)
>>> +
>>> #define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
>>> #define PCI_LATENCY_TIMER 0x0d /* 8 bits */
>>> #define PCI_HEADER_TYPE 0x0e /* 8 bits */
> Putting this in a uapi header means we'll have to support it
> indefinitely. Usually such macros are added to kernel-internal
> headers first and moved to uapi headers if/when the need arises.
>
> Thanks,
>
> Lukas
Apologies for the late response.
The PCI_CLASS_CODE_MASK definition move to include/uapi/linux/pci_regs.h was requested here:
https://lore.kernel.org/linux-cxl/6881626a784f_134cc7100b4@dwillia2-xfh.jf.intel.com.notmuch/
Would you like this patch removed altogether?
Terry
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 10/25] CXL/AER: Update PCI class code check to use FIELD_GET()
2025-10-30 17:16 ` Bowman, Terry
@ 2025-10-31 5:30 ` Lukas Wunner
0 siblings, 0 replies; 92+ messages in thread
From: Lukas Wunner @ 2025-10-31 5:30 UTC (permalink / raw)
To: Bowman, Terry
Cc: Jonathan Cameron, dave, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny,
linux-kernel, linux-pci
On Thu, Oct 30, 2025 at 12:16:06PM -0500, Bowman, Terry wrote:
> On 10/2/2025 2:40 AM, Lukas Wunner wrote:
> > On Wed, Oct 01, 2025 at 05:12:16PM +0100, Jonathan Cameron wrote:
> >> On Thu, 25 Sep 2025 17:34:25 -0500 Terry Bowman <terry.bowman@amd.com> wrote:
> >> The way that class code definitions work in pci_ids.h is somewhat odd
> >> in my opinion, so I'd like input from Bjorn, Lukas etc on whether a
> >> generic mask definition is a good idea or more likely to cause problems.
> >>
> >> See for example.
> >> #define PCI_BASE_CLASS_STORAGE 0x01
> >> ...
> >>
> >> #define PCI_CLASS_STORAGE_SATA 0x0106
> >> #define PCI_CLASS_STORAGE_SATA_AHCI 0x010601
> >>
> >> This variability in what is called CLASS_* leads to fun
> >> situations like in drivers/ata/ahci.c where we have some
> >> PCI_CLASS_* shifted and some not...
> > Macros working with PCI class codes generally accept a "shift" parameter
> > to know by how many bits the class code needs to be shifted, see e.g.
> > DECLARE_PCI_FIXUP_CLASS_EARLY() and friends.
> >
> > A macro which shifts exactly by 8 is hence only of limited use.
> >
> >>> +++ b/drivers/pci/pcie/aer_cxl_rch.c
> >>> @@ -17,10 +17,10 @@ static bool is_cxl_mem_dev(struct pci_dev *dev)
> >>> return false;
> >>>
> >>> /*
> >>> - * CXL Memory Devices must have the 502h class code set (CXL
> >>> - * 3.0, 8.1.12.1).
> >>> + * CXL Memory Devices must have the 502h class code set
> >>> + * (CXL 3.2, 8.1.12.1).
> >>> */
> >>> - if ((dev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> >>> + if (FIELD_GET(PCI_CLASS_CODE_MASK, dev->class) != PCI_CLASS_MEMORY_CXL)
> >>> return false;
> > Hm, this doesn't look more readable TBH.
> >
> > Refactoring changes like this one should be submitted separately from
> > this patch set. If any of them are controversial, they delay upstreaming
> > of the actual change, i.e. the CXL AER plumbing. They also increase the
> > size of the patch set, making it more difficult to review.
> >
> >>> +++ b/include/uapi/linux/pci_regs.h
> >>> @@ -73,6 +73,8 @@
> >>> #define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
> >>> #define PCI_CLASS_DEVICE 0x0a /* Device class */
> >>>
> >>> +#define PCI_CLASS_CODE_MASK __GENMASK(23, 8)
> >>> +
> >>> #define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
> >>> #define PCI_LATENCY_TIMER 0x0d /* 8 bits */
> >>> #define PCI_HEADER_TYPE 0x0e /* 8 bits */
> > Putting this in a uapi header means we'll have to support it
> > indefinitely. Usually such macros are added to kernel-internal
> > headers first and moved to uapi headers if/when the need arises.
>
> The PCI_CLASS_CODE_MASK definition move to include/uapi/linux/pci_regs.h
> was requested here:
> https://lore.kernel.org/linux-cxl/6881626a784f_134cc7100b4@dwillia2-xfh.jf.intel.com.notmuch/
Hm, I'm not seeing such a request in the linked message.
> Would you like this patch removed altogether?
"I wouldn't object to it being removed" would be a more pleasant way
of phrasing it. ;)
Thanks,
Lukas
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 11/25] cxl/pci: Update RAS handler interfaces to also support CXL Ports
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (9 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 10/25] CXL/AER: Update PCI class code check to use FIELD_GET() Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-10-03 20:11 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 12/25] cxl/pci: Log message if RAS registers are unmapped Terry Bowman
` (13 subsequent siblings)
24 siblings, 1 reply; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
CXL PCIe Port Protocol Error handling support will be added to the
CXL drivers in the future. In preparation, rename the existing
interfaces to support handling all CXL PCIe Port Protocol Errors.
The driver's RAS support functions currently rely on a 'struct
cxl_dev_state' type parameter, which is not available for CXL Port
devices. However, since the same CXL RAS capability structure is
needed across most CXL components and devices, a common handling
approach should be adopted.
To accommodate this, update the __cxl_handle_cor_ras() and
__cxl_handle_ras() functions to use a `struct device` instead of
`struct cxl_dev_state`.
No functional changes are introduced.
[1] CXL 3.1 Spec, 8.2.4 CXL.cache and CXL.mem Registers
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Gregory Price <gourry@gourry.net>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
Changes in v11->v12:
- None
Changes in v10->v11:
- None
---
drivers/cxl/core/ras.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 1ec4ea8c56f1..152550bd3547 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -126,8 +126,8 @@ void cxl_ras_exit(void)
cancel_work_sync(&cxl_cper_prot_err_work);
}
-static void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
-static bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
+static void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base);
+static bool cxl_handle_ras(struct device *dev, void __iomem *ras_base);
#ifdef CONFIG_CXL_RCH_RAS
static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
@@ -237,9 +237,9 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
pci_print_aer(pdev, severity, &aer_regs);
if (severity == AER_CORRECTABLE)
- cxl_handle_cor_ras(cxlds, dport->regs.ras);
+ cxl_handle_cor_ras(&cxlds->cxlmd->dev, dport->regs.ras);
else
- cxl_handle_ras(cxlds, dport->regs.ras);
+ cxl_handle_ras(&cxlds->cxlmd->dev, dport->regs.ras);
}
#else
static inline void cxl_dport_map_rch_aer(struct cxl_dport *dport) { }
@@ -281,7 +281,7 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
}
EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
-static void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base)
+static void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base)
{
void __iomem *addr;
u32 status;
@@ -293,7 +293,7 @@ static void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_ba
status = readl(addr);
if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
- trace_cxl_aer_correctable_error(cxlds->cxlmd, status);
+ trace_cxl_aer_correctable_error(to_cxl_memdev(dev), status);
}
}
@@ -318,7 +318,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
* Log the state of the RAS status registers and prepare them to log the
* next error status. Return 1 if reset needed.
*/
-static bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base)
+static bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
{
u32 hl[CXL_HEADERLOG_SIZE_U32];
void __iomem *addr;
@@ -345,7 +345,7 @@ static bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base)
}
header_log_copy(ras_base, hl);
- trace_cxl_aer_uncorrectable_error(cxlds->cxlmd, status, fe, hl);
+ trace_cxl_aer_uncorrectable_error(to_cxl_memdev(dev), status, fe, hl);
writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
return true;
@@ -367,7 +367,7 @@ void cxl_cor_error_detected(struct pci_dev *pdev)
if (cxlds->rcd)
cxl_handle_rdport_errors(cxlds);
- cxl_handle_cor_ras(cxlds, cxlds->regs.ras);
+ cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
}
}
EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
@@ -396,7 +396,7 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
* chance the situation is recoverable dump the status of the RAS
* capability registers and bounce the active state of the memdev.
*/
- ue = cxl_handle_ras(cxlds, cxlds->regs.ras);
+ ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 11/25] cxl/pci: Update RAS handler interfaces to also support CXL Ports
2025-09-25 22:34 ` [PATCH v12 11/25] cxl/pci: Update RAS handler interfaces to also support CXL Ports Terry Bowman
@ 2025-10-03 20:11 ` Cheatham, Benjamin
0 siblings, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:11 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> CXL PCIe Port Protocol Error handling support will be added to the
> CXL drivers in the future. In preparation, rename the existing
> interfaces to support handling all CXL PCIe Port Protocol Errors.
>
> The driver's RAS support functions currently rely on a 'struct
> cxl_dev_state' type parameter, which is not available for CXL Port
> devices. However, since the same CXL RAS capability structure is
> needed across most CXL components and devices, a common handling
> approach should be adopted.
>
> To accommodate this, update the __cxl_handle_cor_ras() and
> __cxl_handle_ras() functions to use a `struct device` instead of
> `struct cxl_dev_state`.
>
> No functional changes are introduced.
>
> [1] CXL 3.1 Spec, 8.2.4 CXL.cache and CXL.mem Registers
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Alejandro Lucero <alucerop@amd.com>
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> Reviewed-by: Gregory Price <gourry@gourry.net>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> ---
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 12/25] cxl/pci: Log message if RAS registers are unmapped
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (10 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 11/25] cxl/pci: Update RAS handler interfaces to also support CXL Ports Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-10-03 20:11 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 13/25] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports Terry Bowman
` (12 subsequent siblings)
24 siblings, 1 reply; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
The CXL RAS handlers do not currently log if the RAS registers are
unmapped. This is needed in order to help debug CXL error handling. Update
the CXL driver to log a warning message if the RAS register block is
unmapped during RAS error handling.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
---
Changes v11->v12:
- None
Changes v10->v11:
- Added Dave Jiang review-by
---
drivers/cxl/core/ras.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 152550bd3547..c66d37d65241 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -286,8 +286,10 @@ static void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base)
void __iomem *addr;
u32 status;
- if (!ras_base)
+ if (!ras_base) {
+ dev_warn_once(dev, "CXL RAS register block is not mapped");
return;
+ }
addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
status = readl(addr);
@@ -325,8 +327,10 @@ static bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
u32 status;
u32 fe;
- if (!ras_base)
+ if (!ras_base) {
+ dev_warn_once(dev, "CXL RAS register block is not mapped");
return false;
+ }
addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
status = readl(addr);
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 12/25] cxl/pci: Log message if RAS registers are unmapped
2025-09-25 22:34 ` [PATCH v12 12/25] cxl/pci: Log message if RAS registers are unmapped Terry Bowman
@ 2025-10-03 20:11 ` Cheatham, Benjamin
0 siblings, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:11 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> The CXL RAS handlers do not currently log if the RAS registers are
> unmapped. This is needed in order to help debug CXL error handling. Update
> the CXL driver to log a warning message if the RAS register block is
> unmapped during RAS error handling.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> ---
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 13/25] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (11 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 12/25] cxl/pci: Log message if RAS registers are unmapped Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-26 20:44 ` Dave Jiang
2025-09-25 22:34 ` [PATCH v12 14/25] cxl/pci: Update cxl_handle_cor_ras() to return early if no RAS errors Terry Bowman
` (11 subsequent siblings)
24 siblings, 1 reply; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
CXL currently has separate trace routines for CXL Port errors and CXL
Endpoint errors. This is inconvenient for the user because they must enable
2 sets of trace routines. Make updates to the trace logging such that a
single trace routine logs both CXL Endpoint and CXL Port protocol errors.
Keep the trace log fields 'memdev' and 'host'. While these are not accurate
for non-Endpoints the fields will remain as-is to prevent breaking
userspace RAS trace consumers.
Add serial number parameter to the trace logging. This is used for EPs
and 0 is provided for CXL port devices without a serial number.
Leave the correctable and uncorrectable trace routines' TP_STRUCT__entry()
unchanged with respect to member data types and order.
Below is output of correctable and uncorrectable protocol error logging.
CXL Root Port and CXL Endpoint examples are included below.
Root Port:
cxl_aer_correctable_error: memdev=0000:0c:00.0 host=pci0000:0c serial: 0 status='CRC Threshold Hit'
cxl_aer_uncorrectable_error: memdev=0000:0c:00.0 host=pci0000:0c serial: 0 status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity Error'
Endpoint:
cxl_aer_correctable_error: memdev=mem3 host=0000:0f:00.0 serial=0 status='CRC Threshold Hit'
cxl_aer_uncorrectable_error: memdev=mem3 host=0000:0f:00.0 serial: 0 status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity Error'
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Shiju Jose <shiju.jose@huawei.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
Changes in v11 -> v12:
- Correct parameters to call trace_cxl_aer_correctable_error()
- Add reviewed-by for Jonathan and Shiju
Changes in v10->v11:
- Updated CE and UCE trace routines to maintain consistent TP_Struct ABI
and unchanged TP_printk() logging.
---
drivers/cxl/core/ras.c | 34 ++++++++++----------
drivers/cxl/core/trace.h | 68 +++++++---------------------------------
2 files changed, 29 insertions(+), 73 deletions(-)
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index c66d37d65241..8a3fbc41b51f 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -13,7 +13,7 @@ static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
{
u32 status = ras_cap.cor_status & ~ras_cap.cor_mask;
- trace_cxl_port_aer_correctable_error(&pdev->dev, status);
+ trace_cxl_aer_correctable_error(&pdev->dev, status, 0);
}
static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
@@ -28,8 +28,8 @@ static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
else
fe = status;
- trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe,
- ras_cap.header_log);
+ trace_cxl_aer_uncorrectable_error(&pdev->dev, status, fe,
+ ras_cap.header_log, 0);
}
static void cxl_cper_trace_corr_prot_err(struct cxl_memdev *cxlmd,
@@ -37,7 +37,7 @@ static void cxl_cper_trace_corr_prot_err(struct cxl_memdev *cxlmd,
{
u32 status = ras_cap.cor_status & ~ras_cap.cor_mask;
- trace_cxl_aer_correctable_error(cxlmd, status);
+ trace_cxl_aer_correctable_error(&cxlmd->dev, status, cxlmd->cxlds->serial);
}
static void
@@ -45,6 +45,7 @@ cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd,
struct cxl_ras_capability_regs ras_cap)
{
u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask;
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
u32 fe;
if (hweight32(status) > 1)
@@ -53,8 +54,9 @@ cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd,
else
fe = status;
- trace_cxl_aer_uncorrectable_error(cxlmd, status, fe,
- ras_cap.header_log);
+ trace_cxl_aer_uncorrectable_error(&cxlmd->dev, status, fe,
+ ras_cap.header_log,
+ cxlds->serial);
}
static int match_memdev_by_parent(struct device *dev, const void *uport)
@@ -126,8 +128,8 @@ void cxl_ras_exit(void)
cancel_work_sync(&cxl_cper_prot_err_work);
}
-static void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base);
-static bool cxl_handle_ras(struct device *dev, void __iomem *ras_base);
+static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base);
+static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
#ifdef CONFIG_CXL_RCH_RAS
static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
@@ -237,9 +239,9 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
pci_print_aer(pdev, severity, &aer_regs);
if (severity == AER_CORRECTABLE)
- cxl_handle_cor_ras(&cxlds->cxlmd->dev, dport->regs.ras);
+ cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
else
- cxl_handle_ras(&cxlds->cxlmd->dev, dport->regs.ras);
+ cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
}
#else
static inline void cxl_dport_map_rch_aer(struct cxl_dport *dport) { }
@@ -281,7 +283,7 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
}
EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
-static void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base)
+static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
{
void __iomem *addr;
u32 status;
@@ -295,7 +297,7 @@ static void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base)
status = readl(addr);
if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
- trace_cxl_aer_correctable_error(to_cxl_memdev(dev), status);
+ trace_cxl_aer_correctable_error(dev, status, serial);
}
}
@@ -320,7 +322,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
* Log the state of the RAS status registers and prepare them to log the
* next error status. Return 1 if reset needed.
*/
-static bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
+static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
{
u32 hl[CXL_HEADERLOG_SIZE_U32];
void __iomem *addr;
@@ -349,7 +351,7 @@ static bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
}
header_log_copy(ras_base, hl);
- trace_cxl_aer_uncorrectable_error(to_cxl_memdev(dev), status, fe, hl);
+ trace_cxl_aer_uncorrectable_error(dev, status, fe, hl, serial);
writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
return true;
@@ -371,7 +373,7 @@ void cxl_cor_error_detected(struct pci_dev *pdev)
if (cxlds->rcd)
cxl_handle_rdport_errors(cxlds);
- cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
+ cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
}
}
EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
@@ -400,7 +402,7 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
* chance the situation is recoverable dump the status of the RAS
* capability registers and bounce the active state of the memdev.
*/
- ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
+ ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
}
diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h
index a53ec4798b12..60b49beb5e3f 100644
--- a/drivers/cxl/core/trace.h
+++ b/drivers/cxl/core/trace.h
@@ -48,40 +48,13 @@
{ CXL_RAS_UC_IDE_RX_ERR, "IDE Rx Error" } \
)
-TRACE_EVENT(cxl_port_aer_uncorrectable_error,
- TP_PROTO(struct device *dev, u32 status, u32 fe, u32 *hl),
- TP_ARGS(dev, status, fe, hl),
- TP_STRUCT__entry(
- __string(device, dev_name(dev))
- __string(host, dev_name(dev->parent))
- __field(u32, status)
- __field(u32, first_error)
- __array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
- ),
- TP_fast_assign(
- __assign_str(device);
- __assign_str(host);
- __entry->status = status;
- __entry->first_error = fe;
- /*
- * Embed the 512B headerlog data for user app retrieval and
- * parsing, but no need to print this in the trace buffer.
- */
- memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
- ),
- TP_printk("device=%s host=%s status: '%s' first_error: '%s'",
- __get_str(device), __get_str(host),
- show_uc_errs(__entry->status),
- show_uc_errs(__entry->first_error)
- )
-);
-
TRACE_EVENT(cxl_aer_uncorrectable_error,
- TP_PROTO(const struct cxl_memdev *cxlmd, u32 status, u32 fe, u32 *hl),
- TP_ARGS(cxlmd, status, fe, hl),
+ TP_PROTO(const struct device *cxlmd, u32 status, u32 fe, u32 *hl,
+ u64 serial),
+ TP_ARGS(cxlmd, status, fe, hl, serial),
TP_STRUCT__entry(
- __string(memdev, dev_name(&cxlmd->dev))
- __string(host, dev_name(cxlmd->dev.parent))
+ __string(memdev, dev_name(cxlmd))
+ __string(host, dev_name(cxlmd->parent))
__field(u64, serial)
__field(u32, status)
__field(u32, first_error)
@@ -90,7 +63,7 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
TP_fast_assign(
__assign_str(memdev);
__assign_str(host);
- __entry->serial = cxlmd->cxlds->serial;
+ __entry->serial = serial;
__entry->status = status;
__entry->first_error = fe;
/*
@@ -124,38 +97,19 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
{ CXL_RAS_CE_PHYS_LAYER_ERR, "Received Error From Physical Layer" } \
)
-TRACE_EVENT(cxl_port_aer_correctable_error,
- TP_PROTO(struct device *dev, u32 status),
- TP_ARGS(dev, status),
- TP_STRUCT__entry(
- __string(device, dev_name(dev))
- __string(host, dev_name(dev->parent))
- __field(u32, status)
- ),
- TP_fast_assign(
- __assign_str(device);
- __assign_str(host);
- __entry->status = status;
- ),
- TP_printk("device=%s host=%s status='%s'",
- __get_str(device), __get_str(host),
- show_ce_errs(__entry->status)
- )
-);
-
TRACE_EVENT(cxl_aer_correctable_error,
- TP_PROTO(const struct cxl_memdev *cxlmd, u32 status),
- TP_ARGS(cxlmd, status),
+ TP_PROTO(const struct device *cxlmd, u32 status, u64 serial),
+ TP_ARGS(cxlmd, status, serial),
TP_STRUCT__entry(
- __string(memdev, dev_name(&cxlmd->dev))
- __string(host, dev_name(cxlmd->dev.parent))
+ __string(memdev, dev_name(cxlmd))
+ __string(host, dev_name(cxlmd->parent))
__field(u64, serial)
__field(u32, status)
),
TP_fast_assign(
__assign_str(memdev);
__assign_str(host);
- __entry->serial = cxlmd->cxlds->serial;
+ __entry->serial = serial;
__entry->status = status;
),
TP_printk("memdev=%s host=%s serial=%lld: status: '%s'",
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 13/25] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
2025-09-25 22:34 ` [PATCH v12 13/25] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports Terry Bowman
@ 2025-09-26 20:44 ` Dave Jiang
0 siblings, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-26 20:44 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> CXL currently has separate trace routines for CXL Port errors and CXL
> Endpoint errors. This is inconvenient for the user because they must enable
> 2 sets of trace routines. Make updates to the trace logging such that a
> single trace routine logs both CXL Endpoint and CXL Port protocol errors.
>
> Keep the trace log fields 'memdev' and 'host'. While these are not accurate
> for non-Endpoints the fields will remain as-is to prevent breaking
> userspace RAS trace consumers.
>
> Add serial number parameter to the trace logging. This is used for EPs
> and 0 is provided for CXL port devices without a serial number.
>
> Leave the correctable and uncorrectable trace routines' TP_STRUCT__entry()
> unchanged with respect to member data types and order.
>
> Below is output of correctable and uncorrectable protocol error logging.
> CXL Root Port and CXL Endpoint examples are included below.
>
> Root Port:
> cxl_aer_correctable_error: memdev=0000:0c:00.0 host=pci0000:0c serial: 0 status='CRC Threshold Hit'
> cxl_aer_uncorrectable_error: memdev=0000:0c:00.0 host=pci0000:0c serial: 0 status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity Error'
>
> Endpoint:
> cxl_aer_correctable_error: memdev=mem3 host=0000:0f:00.0 serial=0 status='CRC Threshold Hit'
> cxl_aer_uncorrectable_error: memdev=mem3 host=0000:0f:00.0 serial: 0 status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity Error'
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Shiju Jose <shiju.jose@huawei.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> ---
>
> Changes in v11 -> v12:
> - Correct parameters to call trace_cxl_aer_correctable_error()
> - Add reviewed-by for Jonathan and Shiju
>
> Changes in v10->v11:
> - Updated CE and UCE trace routines to maintain consistent TP_Struct ABI
> and unchanged TP_printk() logging.
> ---
> drivers/cxl/core/ras.c | 34 ++++++++++----------
> drivers/cxl/core/trace.h | 68 +++++++---------------------------------
> 2 files changed, 29 insertions(+), 73 deletions(-)
>
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index c66d37d65241..8a3fbc41b51f 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -13,7 +13,7 @@ static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
> {
> u32 status = ras_cap.cor_status & ~ras_cap.cor_mask;
>
> - trace_cxl_port_aer_correctable_error(&pdev->dev, status);
> + trace_cxl_aer_correctable_error(&pdev->dev, status, 0);
> }
>
> static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
> @@ -28,8 +28,8 @@ static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
> else
> fe = status;
>
> - trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe,
> - ras_cap.header_log);
> + trace_cxl_aer_uncorrectable_error(&pdev->dev, status, fe,
> + ras_cap.header_log, 0);
> }
>
> static void cxl_cper_trace_corr_prot_err(struct cxl_memdev *cxlmd,
> @@ -37,7 +37,7 @@ static void cxl_cper_trace_corr_prot_err(struct cxl_memdev *cxlmd,
> {
> u32 status = ras_cap.cor_status & ~ras_cap.cor_mask;
>
> - trace_cxl_aer_correctable_error(cxlmd, status);
> + trace_cxl_aer_correctable_error(&cxlmd->dev, status, cxlmd->cxlds->serial);
> }
>
> static void
> @@ -45,6 +45,7 @@ cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd,
> struct cxl_ras_capability_regs ras_cap)
> {
> u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask;
> + struct cxl_dev_state *cxlds = cxlmd->cxlds;
> u32 fe;
>
> if (hweight32(status) > 1)
> @@ -53,8 +54,9 @@ cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd,
> else
> fe = status;
>
> - trace_cxl_aer_uncorrectable_error(cxlmd, status, fe,
> - ras_cap.header_log);
> + trace_cxl_aer_uncorrectable_error(&cxlmd->dev, status, fe,
> + ras_cap.header_log,
> + cxlds->serial);
> }
>
> static int match_memdev_by_parent(struct device *dev, const void *uport)
> @@ -126,8 +128,8 @@ void cxl_ras_exit(void)
> cancel_work_sync(&cxl_cper_prot_err_work);
> }
>
> -static void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base);
> -static bool cxl_handle_ras(struct device *dev, void __iomem *ras_base);
> +static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base);
> +static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>
> #ifdef CONFIG_CXL_RCH_RAS
> static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
> @@ -237,9 +239,9 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
>
> pci_print_aer(pdev, severity, &aer_regs);
> if (severity == AER_CORRECTABLE)
> - cxl_handle_cor_ras(&cxlds->cxlmd->dev, dport->regs.ras);
> + cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
> else
> - cxl_handle_ras(&cxlds->cxlmd->dev, dport->regs.ras);
> + cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
> }
> #else
> static inline void cxl_dport_map_rch_aer(struct cxl_dport *dport) { }
> @@ -281,7 +283,7 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
> }
> EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
>
> -static void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base)
> +static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
> {
> void __iomem *addr;
> u32 status;
> @@ -295,7 +297,7 @@ static void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base)
> status = readl(addr);
> if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
> writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
> - trace_cxl_aer_correctable_error(to_cxl_memdev(dev), status);
> + trace_cxl_aer_correctable_error(dev, status, serial);
> }
> }
>
> @@ -320,7 +322,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
> * Log the state of the RAS status registers and prepare them to log the
> * next error status. Return 1 if reset needed.
> */
> -static bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
> +static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
> {
> u32 hl[CXL_HEADERLOG_SIZE_U32];
> void __iomem *addr;
> @@ -349,7 +351,7 @@ static bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
> }
>
> header_log_copy(ras_base, hl);
> - trace_cxl_aer_uncorrectable_error(to_cxl_memdev(dev), status, fe, hl);
> + trace_cxl_aer_uncorrectable_error(dev, status, fe, hl, serial);
> writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
>
> return true;
> @@ -371,7 +373,7 @@ void cxl_cor_error_detected(struct pci_dev *pdev)
> if (cxlds->rcd)
> cxl_handle_rdport_errors(cxlds);
>
> - cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
> + cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
> }
> }
> EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
> @@ -400,7 +402,7 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
> * chance the situation is recoverable dump the status of the RAS
> * capability registers and bounce the active state of the memdev.
> */
> - ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
> + ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
> }
>
>
> diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h
> index a53ec4798b12..60b49beb5e3f 100644
> --- a/drivers/cxl/core/trace.h
> +++ b/drivers/cxl/core/trace.h
> @@ -48,40 +48,13 @@
> { CXL_RAS_UC_IDE_RX_ERR, "IDE Rx Error" } \
> )
>
> -TRACE_EVENT(cxl_port_aer_uncorrectable_error,
> - TP_PROTO(struct device *dev, u32 status, u32 fe, u32 *hl),
> - TP_ARGS(dev, status, fe, hl),
> - TP_STRUCT__entry(
> - __string(device, dev_name(dev))
> - __string(host, dev_name(dev->parent))
> - __field(u32, status)
> - __field(u32, first_error)
> - __array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
> - ),
> - TP_fast_assign(
> - __assign_str(device);
> - __assign_str(host);
> - __entry->status = status;
> - __entry->first_error = fe;
> - /*
> - * Embed the 512B headerlog data for user app retrieval and
> - * parsing, but no need to print this in the trace buffer.
> - */
> - memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
> - ),
> - TP_printk("device=%s host=%s status: '%s' first_error: '%s'",
> - __get_str(device), __get_str(host),
> - show_uc_errs(__entry->status),
> - show_uc_errs(__entry->first_error)
> - )
> -);
> -
> TRACE_EVENT(cxl_aer_uncorrectable_error,
> - TP_PROTO(const struct cxl_memdev *cxlmd, u32 status, u32 fe, u32 *hl),
> - TP_ARGS(cxlmd, status, fe, hl),
> + TP_PROTO(const struct device *cxlmd, u32 status, u32 fe, u32 *hl,
> + u64 serial),
> + TP_ARGS(cxlmd, status, fe, hl, serial),
> TP_STRUCT__entry(
> - __string(memdev, dev_name(&cxlmd->dev))
> - __string(host, dev_name(cxlmd->dev.parent))
> + __string(memdev, dev_name(cxlmd))
> + __string(host, dev_name(cxlmd->parent))
> __field(u64, serial)
> __field(u32, status)
> __field(u32, first_error)
> @@ -90,7 +63,7 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
> TP_fast_assign(
> __assign_str(memdev);
> __assign_str(host);
> - __entry->serial = cxlmd->cxlds->serial;
> + __entry->serial = serial;
> __entry->status = status;
> __entry->first_error = fe;
> /*
> @@ -124,38 +97,19 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
> { CXL_RAS_CE_PHYS_LAYER_ERR, "Received Error From Physical Layer" } \
> )
>
> -TRACE_EVENT(cxl_port_aer_correctable_error,
> - TP_PROTO(struct device *dev, u32 status),
> - TP_ARGS(dev, status),
> - TP_STRUCT__entry(
> - __string(device, dev_name(dev))
> - __string(host, dev_name(dev->parent))
> - __field(u32, status)
> - ),
> - TP_fast_assign(
> - __assign_str(device);
> - __assign_str(host);
> - __entry->status = status;
> - ),
> - TP_printk("device=%s host=%s status='%s'",
> - __get_str(device), __get_str(host),
> - show_ce_errs(__entry->status)
> - )
> -);
> -
> TRACE_EVENT(cxl_aer_correctable_error,
> - TP_PROTO(const struct cxl_memdev *cxlmd, u32 status),
> - TP_ARGS(cxlmd, status),
> + TP_PROTO(const struct device *cxlmd, u32 status, u64 serial),
> + TP_ARGS(cxlmd, status, serial),
> TP_STRUCT__entry(
> - __string(memdev, dev_name(&cxlmd->dev))
> - __string(host, dev_name(cxlmd->dev.parent))
> + __string(memdev, dev_name(cxlmd))
> + __string(host, dev_name(cxlmd->parent))
> __field(u64, serial)
> __field(u32, status)
> ),
> TP_fast_assign(
> __assign_str(memdev);
> __assign_str(host);
> - __entry->serial = cxlmd->cxlds->serial;
> + __entry->serial = serial;
> __entry->status = status;
> ),
> TP_printk("memdev=%s host=%s serial=%lld: status: '%s'",
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 14/25] cxl/pci: Update cxl_handle_cor_ras() to return early if no RAS errors
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (12 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 13/25] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-10-03 20:11 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 15/25] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers Terry Bowman
` (10 subsequent siblings)
24 siblings, 1 reply; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
Update cxl_handle_cor_ras() to exit early in the case there is no RAS
errors detected after applying the status mask. This change will make
the correctable handler's implementation consistent with the uncorrectable
handler, cxl_handle_ras().
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
---
Changes v11->v12:
- None
Changes v10->v11:
- Added Dave Jiang and Jonathan Cameron's review-by
- Changes moved to core/ras.c
---
drivers/cxl/core/ras.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 8a3fbc41b51f..97a5a5c3910f 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -295,10 +295,11 @@ static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras
addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
status = readl(addr);
- if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
- writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
- trace_cxl_aer_correctable_error(dev, status, serial);
- }
+ if (!(status & CXL_RAS_CORRECTABLE_STATUS_MASK))
+ return;
+ writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
+
+ trace_cxl_aer_correctable_error(dev, status, serial);
}
/* CXL spec rev3.0 8.2.4.16.1 */
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 14/25] cxl/pci: Update cxl_handle_cor_ras() to return early if no RAS errors
2025-09-25 22:34 ` [PATCH v12 14/25] cxl/pci: Update cxl_handle_cor_ras() to return early if no RAS errors Terry Bowman
@ 2025-10-03 20:11 ` Cheatham, Benjamin
0 siblings, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:11 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> Update cxl_handle_cor_ras() to exit early in the case there is no RAS
> errors detected after applying the status mask. This change will make
> the correctable handler's implementation consistent with the uncorrectable
> handler, cxl_handle_ras().
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> ---
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 15/25] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (13 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 14/25] cxl/pci: Update cxl_handle_cor_ras() to return early if no RAS errors Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-26 21:10 ` Dave Jiang
2025-09-25 22:34 ` [PATCH v12 16/25] CXL/PCI: Introduce PCI_ERS_RESULT_PANIC Terry Bowman
` (9 subsequent siblings)
24 siblings, 1 reply; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
CXL Endpoint (EP) Ports may include Root Ports (RP) or Downstream Switch
Ports (DSP). CXL RPs and DSPs contain RAS registers that require memory
mapping to enable RAS logging. This initialization is currently missing and
must be added for CXL RPs and DSPs.
Update cxl_dport_init_ras_reporting() to support RP and DSP RAS mapping.
Add alongside the existing Restricted CXL Host Downstream Port RAS mapping.
Update cxl_endpoint_port_probe() to invoke cxl_dport_init_ras_reporting().
This will initiate the RAS mapping for CXL RPs and DSPs when each CXL EP is
created and added to the EP port.
Make a call to cxl_port_setup_regs() in cxl_port_add(). This will probe the
Upstream Port's CXL capabilities' physical location to be used in mapping
the RAS registers.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
Changes in v11->v12:
- Add check for dport_parent->rch before calling cxl_dport_init_ras_reporting().
RCH dports are initialized from cxl_dport_init_ras_reporting cxl_mem_probe().
Changes in v10->v11:
- Use local pointer for readability in cxl_switch_port_init_ras() (Jonathan Cameron)
- Rename port to be ep in cxl_endpoint_port_init_ras() (Dave Jiang)
- Rename dport to be parent_dport in cxl_endpoint_port_init_ras()
and cxl_switch_port_init_ras() (Dave Jiang)
- Port helper changes were in cxl/port.c, now in core/ras.c (Dave
Jiang)
---
drivers/cxl/core/core.h | 7 ++++++
drivers/cxl/core/port.c | 1 +
drivers/cxl/core/ras.c | 48 +++++++++++++++++++++++++++++++++++++++++
drivers/cxl/cxl.h | 2 ++
drivers/cxl/cxlpci.h | 4 ----
drivers/cxl/mem.c | 4 +++-
drivers/cxl/port.c | 5 +++++
7 files changed, 66 insertions(+), 5 deletions(-)
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 9f4eb7e2feba..8c51a2631716 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -147,6 +147,9 @@ int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
#ifdef CONFIG_CXL_RAS
int cxl_ras_init(void);
void cxl_ras_exit(void);
+void cxl_switch_port_init_ras(struct cxl_port *port);
+void cxl_endpoint_port_init_ras(struct cxl_port *ep);
+void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
#else
static inline int cxl_ras_init(void)
{
@@ -156,6 +159,10 @@ static inline int cxl_ras_init(void)
static inline void cxl_ras_exit(void)
{
}
+static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
+static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
+static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
+ struct device *host) { }
#endif // CONFIG_CXL_RAS
int cxl_gpf_port_setup(struct cxl_dport *dport);
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index d5f71eb1ade8..bd4be046888a 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -870,6 +870,7 @@ static int cxl_port_add(struct cxl_port *port,
return rc;
port->component_reg_phys = component_reg_phys;
+ cxl_port_setup_regs(port, port->component_reg_phys);
} else {
rc = dev_set_name(dev, "root%d", port->id);
if (rc)
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 97a5a5c3910f..14a434bd68f0 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -283,6 +283,54 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
}
EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
+static void cxl_uport_init_ras_reporting(struct cxl_port *port,
+ struct device *host)
+{
+ struct cxl_register_map *map = &port->reg_map;
+
+ map->host = host;
+ if (cxl_map_component_regs(map, &port->uport_regs,
+ BIT(CXL_CM_CAP_CAP_ID_RAS)))
+ dev_dbg(&port->dev, "Failed to map RAS capability\n");
+}
+
+void cxl_switch_port_init_ras(struct cxl_port *port)
+{
+ struct cxl_dport *parent_dport = port->parent_dport;
+
+ if (is_cxl_root(to_cxl_port(port->dev.parent)))
+ return;
+
+ /* May have parent DSP or RP */
+ if (parent_dport && dev_is_pci(parent_dport->dport_dev) &&
+ !parent_dport->rch) {
+ struct pci_dev *pdev = to_pci_dev(parent_dport->dport_dev);
+
+ if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
+ (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM))
+ cxl_dport_init_ras_reporting(parent_dport, &port->dev);
+ }
+
+ cxl_uport_init_ras_reporting(port, &port->dev);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_switch_port_init_ras, "CXL");
+
+void cxl_endpoint_port_init_ras(struct cxl_port *ep)
+{
+ struct cxl_dport *parent_dport;
+ struct cxl_memdev *cxlmd = to_cxl_memdev(ep->uport_dev);
+ struct cxl_port *parent_port __free(put_cxl_port) =
+ cxl_mem_find_port(cxlmd, &parent_dport);
+
+ if (!parent_dport || !dev_is_pci(parent_dport->dport_dev) || parent_dport->rch) {
+ dev_err(&ep->dev, "CXL port topology not found\n");
+ return;
+ }
+
+ cxl_dport_init_ras_reporting(parent_dport, cxlmd->cxlds->dev);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
+
static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
{
void __iomem *addr;
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 259ed4b676e1..b7654d40dc9e 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -599,6 +599,7 @@ struct cxl_dax_region {
* @parent_dport: dport that points to this port in the parent
* @decoder_ida: allocator for decoder ids
* @reg_map: component and ras register mapping parameters
+ * @uport_regs: mapped component registers
* @nr_dports: number of entries in @dports
* @hdm_end: track last allocated HDM decoder instance for allocation ordering
* @commit_end: cursor to track highest committed decoder for commit ordering
@@ -620,6 +621,7 @@ struct cxl_port {
struct cxl_dport *parent_dport;
struct ida decoder_ida;
struct cxl_register_map reg_map;
+ struct cxl_component_regs uport_regs;
int nr_dports;
int hdm_end;
int commit_end;
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 0c8b6ee7b6de..3882a089ae77 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -82,7 +82,6 @@ void read_cdat_data(struct cxl_port *port);
void cxl_cor_error_detected(struct pci_dev *pdev);
pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
pci_channel_state_t state);
-void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
#else
static inline void cxl_cor_error_detected(struct pci_dev *pdev) { }
@@ -91,9 +90,6 @@ static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
{
return PCI_ERS_RESULT_NONE;
}
-
-static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
- struct device *host) { }
#endif
#endif /* __CXL_PCI_H__ */
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index 6e6777b7bafb..f7dc0ba8905d 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -7,6 +7,7 @@
#include "cxlmem.h"
#include "cxlpci.h"
+#include "core/core.h"
/**
* DOC: cxl mem
@@ -166,7 +167,8 @@ static int cxl_mem_probe(struct device *dev)
else
endpoint_parent = &parent_port->dev;
- cxl_dport_init_ras_reporting(dport, dev);
+ if (dport->rch)
+ cxl_dport_init_ras_reporting(dport, dev);
scoped_guard(device, endpoint_parent) {
if (!endpoint_parent->driver) {
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 51c8f2f84717..2d12890b66fe 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -6,6 +6,7 @@
#include "cxlmem.h"
#include "cxlpci.h"
+#include "core/core.h"
/**
* DOC: cxl port
@@ -65,6 +66,8 @@ static int cxl_switch_port_probe(struct cxl_port *port)
/* Cache the data early to ensure is_visible() works */
read_cdat_data(port);
+ cxl_switch_port_init_ras(port);
+
return 0;
}
@@ -86,6 +89,8 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
if (rc)
return rc;
+ cxl_endpoint_port_init_ras(port);
+
/*
* Now that all endpoint decoders are successfully enumerated, try to
* assemble regions from committed decoders
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 15/25] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
2025-09-25 22:34 ` [PATCH v12 15/25] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers Terry Bowman
@ 2025-09-26 21:10 ` Dave Jiang
2025-10-24 10:25 ` Alejandro Lucero Palau
0 siblings, 1 reply; 92+ messages in thread
From: Dave Jiang @ 2025-09-26 21:10 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> CXL Endpoint (EP) Ports may include Root Ports (RP) or Downstream Switch
> Ports (DSP). CXL RPs and DSPs contain RAS registers that require memory
> mapping to enable RAS logging. This initialization is currently missing and
> must be added for CXL RPs and DSPs.
>
> Update cxl_dport_init_ras_reporting() to support RP and DSP RAS mapping.
> Add alongside the existing Restricted CXL Host Downstream Port RAS mapping.
>
> Update cxl_endpoint_port_probe() to invoke cxl_dport_init_ras_reporting().
> This will initiate the RAS mapping for CXL RPs and DSPs when each CXL EP is
> created and added to the EP port.
>
> Make a call to cxl_port_setup_regs() in cxl_port_add(). This will probe the
> Upstream Port's CXL capabilities' physical location to be used in mapping
> the RAS registers.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>
> ---
>
> Changes in v11->v12:
> - Add check for dport_parent->rch before calling cxl_dport_init_ras_reporting().
> RCH dports are initialized from cxl_dport_init_ras_reporting cxl_mem_probe().
>
> Changes in v10->v11:
> - Use local pointer for readability in cxl_switch_port_init_ras() (Jonathan Cameron)
> - Rename port to be ep in cxl_endpoint_port_init_ras() (Dave Jiang)
> - Rename dport to be parent_dport in cxl_endpoint_port_init_ras()
> and cxl_switch_port_init_ras() (Dave Jiang)
> - Port helper changes were in cxl/port.c, now in core/ras.c (Dave
> Jiang)
> ---
> drivers/cxl/core/core.h | 7 ++++++
> drivers/cxl/core/port.c | 1 +
> drivers/cxl/core/ras.c | 48 +++++++++++++++++++++++++++++++++++++++++
> drivers/cxl/cxl.h | 2 ++
> drivers/cxl/cxlpci.h | 4 ----
> drivers/cxl/mem.c | 4 +++-
> drivers/cxl/port.c | 5 +++++
> 7 files changed, 66 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
> index 9f4eb7e2feba..8c51a2631716 100644
> --- a/drivers/cxl/core/core.h
> +++ b/drivers/cxl/core/core.h
> @@ -147,6 +147,9 @@ int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
> #ifdef CONFIG_CXL_RAS
> int cxl_ras_init(void);
> void cxl_ras_exit(void);
> +void cxl_switch_port_init_ras(struct cxl_port *port);
> +void cxl_endpoint_port_init_ras(struct cxl_port *ep);
> +void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
> #else
> static inline int cxl_ras_init(void)
> {
> @@ -156,6 +159,10 @@ static inline int cxl_ras_init(void)
> static inline void cxl_ras_exit(void)
> {
> }
> +static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
> +static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
> +static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
> + struct device *host) { }
> #endif // CONFIG_CXL_RAS
>
> int cxl_gpf_port_setup(struct cxl_dport *dport);
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index d5f71eb1ade8..bd4be046888a 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -870,6 +870,7 @@ static int cxl_port_add(struct cxl_port *port,
> return rc;
>
> port->component_reg_phys = component_reg_phys;
> + cxl_port_setup_regs(port, port->component_reg_phys);
This was actually moved previously to delay the port register probe. It now happens when the first dport is discovered. See the end of __devm_cxl_add_dport().
> } else {
> rc = dev_set_name(dev, "root%d", port->id);
> if (rc)
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 97a5a5c3910f..14a434bd68f0 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -283,6 +283,54 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
> }
> EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
>
> +static void cxl_uport_init_ras_reporting(struct cxl_port *port,
> + struct device *host)
> +{
> + struct cxl_register_map *map = &port->reg_map;
> +
> + map->host = host;
> + if (cxl_map_component_regs(map, &port->uport_regs,
> + BIT(CXL_CM_CAP_CAP_ID_RAS)))
> + dev_dbg(&port->dev, "Failed to map RAS capability\n");
> +}
> +
> +void cxl_switch_port_init_ras(struct cxl_port *port)
> +{
> + struct cxl_dport *parent_dport = port->parent_dport;
> +
> + if (is_cxl_root(to_cxl_port(port->dev.parent)))
> + return;
> +
> + /* May have parent DSP or RP */
> + if (parent_dport && dev_is_pci(parent_dport->dport_dev) &&
> + !parent_dport->rch) {
> + struct pci_dev *pdev = to_pci_dev(parent_dport->dport_dev);
> +
> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM))
> + cxl_dport_init_ras_reporting(parent_dport, &port->dev);
> + }
> +
> + cxl_uport_init_ras_reporting(port, &port->dev);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_switch_port_init_ras, "CXL");
> +
> +void cxl_endpoint_port_init_ras(struct cxl_port *ep)
> +{
> + struct cxl_dport *parent_dport;
> + struct cxl_memdev *cxlmd = to_cxl_memdev(ep->uport_dev);
> + struct cxl_port *parent_port __free(put_cxl_port) =
> + cxl_mem_find_port(cxlmd, &parent_dport);
> +
> + if (!parent_dport || !dev_is_pci(parent_dport->dport_dev) || parent_dport->rch) {
> + dev_err(&ep->dev, "CXL port topology not found\n");
> + return;
> + }
> +
> + cxl_dport_init_ras_reporting(parent_dport, cxlmd->cxlds->dev);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
> +
> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
> {
> void __iomem *addr;
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 259ed4b676e1..b7654d40dc9e 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -599,6 +599,7 @@ struct cxl_dax_region {
> * @parent_dport: dport that points to this port in the parent
> * @decoder_ida: allocator for decoder ids
> * @reg_map: component and ras register mapping parameters
> + * @uport_regs: mapped component registers
> * @nr_dports: number of entries in @dports
> * @hdm_end: track last allocated HDM decoder instance for allocation ordering
> * @commit_end: cursor to track highest committed decoder for commit ordering
> @@ -620,6 +621,7 @@ struct cxl_port {
> struct cxl_dport *parent_dport;
> struct ida decoder_ida;
> struct cxl_register_map reg_map;
> + struct cxl_component_regs uport_regs;
> int nr_dports;
> int hdm_end;
> int commit_end;
> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
> index 0c8b6ee7b6de..3882a089ae77 100644
> --- a/drivers/cxl/cxlpci.h
> +++ b/drivers/cxl/cxlpci.h
> @@ -82,7 +82,6 @@ void read_cdat_data(struct cxl_port *port);
> void cxl_cor_error_detected(struct pci_dev *pdev);
> pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
> pci_channel_state_t state);
> -void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
> #else
> static inline void cxl_cor_error_detected(struct pci_dev *pdev) { }
>
> @@ -91,9 +90,6 @@ static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
> {
> return PCI_ERS_RESULT_NONE;
> }
> -
> -static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
> - struct device *host) { }
> #endif
>
> #endif /* __CXL_PCI_H__ */
I think this change broke cxl_test:
CC [M] test/mem.o
test/mock.c: In function ‘__wrap_cxl_dport_init_ras_reporting’:
test/mock.c:266:17: error: implicit declaration of function ‘cxl_dport_init_ras_reporting’ [-Wimplicit-function-declaration]
266 | cxl_dport_init_ras_reporting(dport, host);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
> index 6e6777b7bafb..f7dc0ba8905d 100644
> --- a/drivers/cxl/mem.c
> +++ b/drivers/cxl/mem.c
> @@ -7,6 +7,7 @@
>
> #include "cxlmem.h"
> #include "cxlpci.h"
> +#include "core/core.h"
>
> /**
> * DOC: cxl mem
> @@ -166,7 +167,8 @@ static int cxl_mem_probe(struct device *dev)
> else
> endpoint_parent = &parent_port->dev;
>
> - cxl_dport_init_ras_reporting(dport, dev);
> + if (dport->rch)
> + cxl_dport_init_ras_reporting(dport, dev);
>
> scoped_guard(device, endpoint_parent) {
> if (!endpoint_parent->driver) {
> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
> index 51c8f2f84717..2d12890b66fe 100644
> --- a/drivers/cxl/port.c
> +++ b/drivers/cxl/port.c
> @@ -6,6 +6,7 @@
>
> #include "cxlmem.h"
> #include "cxlpci.h"
> +#include "core/core.h"
>
> /**
> * DOC: cxl port
> @@ -65,6 +66,8 @@ static int cxl_switch_port_probe(struct cxl_port *port)
> /* Cache the data early to ensure is_visible() works */
> read_cdat_data(port);
>
> + cxl_switch_port_init_ras(port);
This is probably not the right place to do it because you have no dports yet with the new delayed dport setup. I would init the uport when the register gets probed in __devm_cxl_add_dport(), and init the dport on per dport basis as they are discovered. So maybe in cxl_port_add_dport(). This is where the old dport stuff in the switch probe got moved to.
> +
> return 0;
> }
>
> @@ -86,6 +89,8 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
> if (rc)
> return rc;
>
> + cxl_endpoint_port_init_ras(port);
> +
> /*
> * Now that all endpoint decoders are successfully enumerated, try to
> * assemble regions from committed decoders
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 15/25] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
2025-09-26 21:10 ` Dave Jiang
@ 2025-10-24 10:25 ` Alejandro Lucero Palau
2025-10-24 17:15 ` Dave Jiang
2025-10-24 19:40 ` Bowman, Terry
0 siblings, 2 replies; 92+ messages in thread
From: Alejandro Lucero Palau @ 2025-10-24 10:25 UTC (permalink / raw)
To: Dave Jiang, Terry Bowman, dave, jonathan.cameron,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, ira.weiny
Cc: linux-kernel, linux-pci
On 9/26/25 22:10, Dave Jiang wrote:
>
> On 9/25/25 3:34 PM, Terry Bowman wrote:
>> CXL Endpoint (EP) Ports may include Root Ports (RP) or Downstream Switch
>> Ports (DSP). CXL RPs and DSPs contain RAS registers that require memory
>> mapping to enable RAS logging. This initialization is currently missing and
>> must be added for CXL RPs and DSPs.
>>
>> Update cxl_dport_init_ras_reporting() to support RP and DSP RAS mapping.
>> Add alongside the existing Restricted CXL Host Downstream Port RAS mapping.
>>
>> Update cxl_endpoint_port_probe() to invoke cxl_dport_init_ras_reporting().
>> This will initiate the RAS mapping for CXL RPs and DSPs when each CXL EP is
>> created and added to the EP port.
>>
>> Make a call to cxl_port_setup_regs() in cxl_port_add(). This will probe the
>> Upstream Port's CXL capabilities' physical location to be used in mapping
>> the RAS registers.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>
>> ---
>>
>> Changes in v11->v12:
>> - Add check for dport_parent->rch before calling cxl_dport_init_ras_reporting().
>> RCH dports are initialized from cxl_dport_init_ras_reporting cxl_mem_probe().
>>
>> Changes in v10->v11:
>> - Use local pointer for readability in cxl_switch_port_init_ras() (Jonathan Cameron)
>> - Rename port to be ep in cxl_endpoint_port_init_ras() (Dave Jiang)
>> - Rename dport to be parent_dport in cxl_endpoint_port_init_ras()
>> and cxl_switch_port_init_ras() (Dave Jiang)
>> - Port helper changes were in cxl/port.c, now in core/ras.c (Dave
>> Jiang)
>> ---
>> drivers/cxl/core/core.h | 7 ++++++
>> drivers/cxl/core/port.c | 1 +
>> drivers/cxl/core/ras.c | 48 +++++++++++++++++++++++++++++++++++++++++
>> drivers/cxl/cxl.h | 2 ++
>> drivers/cxl/cxlpci.h | 4 ----
>> drivers/cxl/mem.c | 4 +++-
>> drivers/cxl/port.c | 5 +++++
>> 7 files changed, 66 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
>> index 9f4eb7e2feba..8c51a2631716 100644
>> --- a/drivers/cxl/core/core.h
>> +++ b/drivers/cxl/core/core.h
>> @@ -147,6 +147,9 @@ int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
>> #ifdef CONFIG_CXL_RAS
>> int cxl_ras_init(void);
>> void cxl_ras_exit(void);
>> +void cxl_switch_port_init_ras(struct cxl_port *port);
>> +void cxl_endpoint_port_init_ras(struct cxl_port *ep);
>> +void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>> #else
>> static inline int cxl_ras_init(void)
>> {
>> @@ -156,6 +159,10 @@ static inline int cxl_ras_init(void)
>> static inline void cxl_ras_exit(void)
>> {
>> }
>> +static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
>> +static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
>> +static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>> + struct device *host) { }
>> #endif // CONFIG_CXL_RAS
>>
>> int cxl_gpf_port_setup(struct cxl_dport *dport);
>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>> index d5f71eb1ade8..bd4be046888a 100644
>> --- a/drivers/cxl/core/port.c
>> +++ b/drivers/cxl/core/port.c
>> @@ -870,6 +870,7 @@ static int cxl_port_add(struct cxl_port *port,
>> return rc;
>>
>> port->component_reg_phys = component_reg_phys;
>> + cxl_port_setup_regs(port, port->component_reg_phys);
> This was actually moved previously to delay the port register probe. It now happens when the first dport is discovered. See the end of __devm_cxl_add_dport().
FWIW (other people not going through my discovery path :-) ) Dave is
pointing out to his patchset for delaying port probing and now applied
to next.
Terry, any estimation of when your next version will be sent to the
list? My Type2 patchset is dependent on yours, so I'll be reviewing it
as soon as you do it.
Thank you
>> } else {
>> rc = dev_set_name(dev, "root%d", port->id);
>> if (rc)
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 97a5a5c3910f..14a434bd68f0 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -283,6 +283,54 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
>> }
>> EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
>>
>> +static void cxl_uport_init_ras_reporting(struct cxl_port *port,
>> + struct device *host)
>> +{
>> + struct cxl_register_map *map = &port->reg_map;
>> +
>> + map->host = host;
>> + if (cxl_map_component_regs(map, &port->uport_regs,
>> + BIT(CXL_CM_CAP_CAP_ID_RAS)))
>> + dev_dbg(&port->dev, "Failed to map RAS capability\n");
>> +}
>> +
>> +void cxl_switch_port_init_ras(struct cxl_port *port)
>> +{
>> + struct cxl_dport *parent_dport = port->parent_dport;
>> +
>> + if (is_cxl_root(to_cxl_port(port->dev.parent)))
>> + return;
>> +
>> + /* May have parent DSP or RP */
>> + if (parent_dport && dev_is_pci(parent_dport->dport_dev) &&
>> + !parent_dport->rch) {
>> + struct pci_dev *pdev = to_pci_dev(parent_dport->dport_dev);
>> +
>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM))
>> + cxl_dport_init_ras_reporting(parent_dport, &port->dev);
>> + }
>> +
>> + cxl_uport_init_ras_reporting(port, &port->dev);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_switch_port_init_ras, "CXL");
>> +
>> +void cxl_endpoint_port_init_ras(struct cxl_port *ep)
>> +{
>> + struct cxl_dport *parent_dport;
>> + struct cxl_memdev *cxlmd = to_cxl_memdev(ep->uport_dev);
>> + struct cxl_port *parent_port __free(put_cxl_port) =
>> + cxl_mem_find_port(cxlmd, &parent_dport);
>> +
>> + if (!parent_dport || !dev_is_pci(parent_dport->dport_dev) || parent_dport->rch) {
>> + dev_err(&ep->dev, "CXL port topology not found\n");
>> + return;
>> + }
>> +
>> + cxl_dport_init_ras_reporting(parent_dport, cxlmd->cxlds->dev);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>> +
>> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>> {
>> void __iomem *addr;
>> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
>> index 259ed4b676e1..b7654d40dc9e 100644
>> --- a/drivers/cxl/cxl.h
>> +++ b/drivers/cxl/cxl.h
>> @@ -599,6 +599,7 @@ struct cxl_dax_region {
>> * @parent_dport: dport that points to this port in the parent
>> * @decoder_ida: allocator for decoder ids
>> * @reg_map: component and ras register mapping parameters
>> + * @uport_regs: mapped component registers
>> * @nr_dports: number of entries in @dports
>> * @hdm_end: track last allocated HDM decoder instance for allocation ordering
>> * @commit_end: cursor to track highest committed decoder for commit ordering
>> @@ -620,6 +621,7 @@ struct cxl_port {
>> struct cxl_dport *parent_dport;
>> struct ida decoder_ida;
>> struct cxl_register_map reg_map;
>> + struct cxl_component_regs uport_regs;
>> int nr_dports;
>> int hdm_end;
>> int commit_end;
>> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
>> index 0c8b6ee7b6de..3882a089ae77 100644
>> --- a/drivers/cxl/cxlpci.h
>> +++ b/drivers/cxl/cxlpci.h
>> @@ -82,7 +82,6 @@ void read_cdat_data(struct cxl_port *port);
>> void cxl_cor_error_detected(struct pci_dev *pdev);
>> pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>> pci_channel_state_t state);
>> -void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>> #else
>> static inline void cxl_cor_error_detected(struct pci_dev *pdev) { }
>>
>> @@ -91,9 +90,6 @@ static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>> {
>> return PCI_ERS_RESULT_NONE;
>> }
>> -
>> -static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>> - struct device *host) { }
>> #endif
>>
>> #endif /* __CXL_PCI_H__ */
> I think this change broke cxl_test:
>
> CC [M] test/mem.o
> test/mock.c: In function ‘__wrap_cxl_dport_init_ras_reporting’:
> test/mock.c:266:17: error: implicit declaration of function ‘cxl_dport_init_ras_reporting’ [-Wimplicit-function-declaration]
> 266 | cxl_dport_init_ras_reporting(dport, host);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
>
>> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
>> index 6e6777b7bafb..f7dc0ba8905d 100644
>> --- a/drivers/cxl/mem.c
>> +++ b/drivers/cxl/mem.c
>> @@ -7,6 +7,7 @@
>>
>> #include "cxlmem.h"
>> #include "cxlpci.h"
>> +#include "core/core.h"
>>
>> /**
>> * DOC: cxl mem
>> @@ -166,7 +167,8 @@ static int cxl_mem_probe(struct device *dev)
>> else
>> endpoint_parent = &parent_port->dev;
>>
>> - cxl_dport_init_ras_reporting(dport, dev);
>> + if (dport->rch)
>> + cxl_dport_init_ras_reporting(dport, dev);
>>
>> scoped_guard(device, endpoint_parent) {
>> if (!endpoint_parent->driver) {
>> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
>> index 51c8f2f84717..2d12890b66fe 100644
>> --- a/drivers/cxl/port.c
>> +++ b/drivers/cxl/port.c
>> @@ -6,6 +6,7 @@
>>
>> #include "cxlmem.h"
>> #include "cxlpci.h"
>> +#include "core/core.h"
>>
>> /**
>> * DOC: cxl port
>> @@ -65,6 +66,8 @@ static int cxl_switch_port_probe(struct cxl_port *port)
>> /* Cache the data early to ensure is_visible() works */
>> read_cdat_data(port);
>>
>> + cxl_switch_port_init_ras(port);
> This is probably not the right place to do it because you have no dports yet with the new delayed dport setup. I would init the uport when the register gets probed in __devm_cxl_add_dport(), and init the dport on per dport basis as they are discovered. So maybe in cxl_port_add_dport(). This is where the old dport stuff in the switch probe got moved to.
>
>> +
>> return 0;
>> }
>>
>> @@ -86,6 +89,8 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
>> if (rc)
>> return rc;
>>
>> + cxl_endpoint_port_init_ras(port);
>> +
>> /*
>> * Now that all endpoint decoders are successfully enumerated, try to
>> * assemble regions from committed decoders
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 15/25] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
2025-10-24 10:25 ` Alejandro Lucero Palau
@ 2025-10-24 17:15 ` Dave Jiang
2025-10-24 19:40 ` Bowman, Terry
1 sibling, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-10-24 17:15 UTC (permalink / raw)
To: Alejandro Lucero Palau, Terry Bowman, dave, jonathan.cameron,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, ira.weiny
Cc: linux-kernel, linux-pci
On 10/24/25 3:25 AM, Alejandro Lucero Palau wrote:
>
> On 9/26/25 22:10, Dave Jiang wrote:
>>
>> On 9/25/25 3:34 PM, Terry Bowman wrote:
>>> CXL Endpoint (EP) Ports may include Root Ports (RP) or Downstream Switch
>>> Ports (DSP). CXL RPs and DSPs contain RAS registers that require memory
>>> mapping to enable RAS logging. This initialization is currently missing and
>>> must be added for CXL RPs and DSPs.
>>>
>>> Update cxl_dport_init_ras_reporting() to support RP and DSP RAS mapping.
>>> Add alongside the existing Restricted CXL Host Downstream Port RAS mapping.
>>>
>>> Update cxl_endpoint_port_probe() to invoke cxl_dport_init_ras_reporting().
>>> This will initiate the RAS mapping for CXL RPs and DSPs when each CXL EP is
>>> created and added to the EP port.
>>>
>>> Make a call to cxl_port_setup_regs() in cxl_port_add(). This will probe the
>>> Upstream Port's CXL capabilities' physical location to be used in mapping
>>> the RAS registers.
>>>
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>>
>>> ---
>>>
>>> Changes in v11->v12:
>>> - Add check for dport_parent->rch before calling cxl_dport_init_ras_reporting().
>>> RCH dports are initialized from cxl_dport_init_ras_reporting cxl_mem_probe().
>>>
>>> Changes in v10->v11:
>>> - Use local pointer for readability in cxl_switch_port_init_ras() (Jonathan Cameron)
>>> - Rename port to be ep in cxl_endpoint_port_init_ras() (Dave Jiang)
>>> - Rename dport to be parent_dport in cxl_endpoint_port_init_ras()
>>> and cxl_switch_port_init_ras() (Dave Jiang)
>>> - Port helper changes were in cxl/port.c, now in core/ras.c (Dave
>>> Jiang)
>>> ---
>>> drivers/cxl/core/core.h | 7 ++++++
>>> drivers/cxl/core/port.c | 1 +
>>> drivers/cxl/core/ras.c | 48 +++++++++++++++++++++++++++++++++++++++++
>>> drivers/cxl/cxl.h | 2 ++
>>> drivers/cxl/cxlpci.h | 4 ----
>>> drivers/cxl/mem.c | 4 +++-
>>> drivers/cxl/port.c | 5 +++++
>>> 7 files changed, 66 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
>>> index 9f4eb7e2feba..8c51a2631716 100644
>>> --- a/drivers/cxl/core/core.h
>>> +++ b/drivers/cxl/core/core.h
>>> @@ -147,6 +147,9 @@ int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
>>> #ifdef CONFIG_CXL_RAS
>>> int cxl_ras_init(void);
>>> void cxl_ras_exit(void);
>>> +void cxl_switch_port_init_ras(struct cxl_port *port);
>>> +void cxl_endpoint_port_init_ras(struct cxl_port *ep);
>>> +void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>>> #else
>>> static inline int cxl_ras_init(void)
>>> {
>>> @@ -156,6 +159,10 @@ static inline int cxl_ras_init(void)
>>> static inline void cxl_ras_exit(void)
>>> {
>>> }
>>> +static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
>>> +static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
>>> +static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>>> + struct device *host) { }
>>> #endif // CONFIG_CXL_RAS
>>> int cxl_gpf_port_setup(struct cxl_dport *dport);
>>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>>> index d5f71eb1ade8..bd4be046888a 100644
>>> --- a/drivers/cxl/core/port.c
>>> +++ b/drivers/cxl/core/port.c
>>> @@ -870,6 +870,7 @@ static int cxl_port_add(struct cxl_port *port,
>>> return rc;
>>> port->component_reg_phys = component_reg_phys;
>>> + cxl_port_setup_regs(port, port->component_reg_phys);
>> This was actually moved previously to delay the port register probe. It now happens when the first dport is discovered. See the end of __devm_cxl_add_dport().
>
>
> FWIW (other people not going through my discovery path :-) ) Dave is pointing out to his patchset for delaying port probing and now applied to next.
It's in 6.18-rc now.
DJ
>
>
> Terry, any estimation of when your next version will be sent to the list? My Type2 patchset is dependent on yours, so I'll be reviewing it as soon as you do it.
>
>
> Thank you
>
>
>>> } else {
>>> rc = dev_set_name(dev, "root%d", port->id);
>>> if (rc)
>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>> index 97a5a5c3910f..14a434bd68f0 100644
>>> --- a/drivers/cxl/core/ras.c
>>> +++ b/drivers/cxl/core/ras.c
>>> @@ -283,6 +283,54 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
>>> }
>>> EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
>>> +static void cxl_uport_init_ras_reporting(struct cxl_port *port,
>>> + struct device *host)
>>> +{
>>> + struct cxl_register_map *map = &port->reg_map;
>>> +
>>> + map->host = host;
>>> + if (cxl_map_component_regs(map, &port->uport_regs,
>>> + BIT(CXL_CM_CAP_CAP_ID_RAS)))
>>> + dev_dbg(&port->dev, "Failed to map RAS capability\n");
>>> +}
>>> +
>>> +void cxl_switch_port_init_ras(struct cxl_port *port)
>>> +{
>>> + struct cxl_dport *parent_dport = port->parent_dport;
>>> +
>>> + if (is_cxl_root(to_cxl_port(port->dev.parent)))
>>> + return;
>>> +
>>> + /* May have parent DSP or RP */
>>> + if (parent_dport && dev_is_pci(parent_dport->dport_dev) &&
>>> + !parent_dport->rch) {
>>> + struct pci_dev *pdev = to_pci_dev(parent_dport->dport_dev);
>>> +
>>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM))
>>> + cxl_dport_init_ras_reporting(parent_dport, &port->dev);
>>> + }
>>> +
>>> + cxl_uport_init_ras_reporting(port, &port->dev);
>>> +}
>>> +EXPORT_SYMBOL_NS_GPL(cxl_switch_port_init_ras, "CXL");
>>> +
>>> +void cxl_endpoint_port_init_ras(struct cxl_port *ep)
>>> +{
>>> + struct cxl_dport *parent_dport;
>>> + struct cxl_memdev *cxlmd = to_cxl_memdev(ep->uport_dev);
>>> + struct cxl_port *parent_port __free(put_cxl_port) =
>>> + cxl_mem_find_port(cxlmd, &parent_dport);
>>> +
>>> + if (!parent_dport || !dev_is_pci(parent_dport->dport_dev) || parent_dport->rch) {
>>> + dev_err(&ep->dev, "CXL port topology not found\n");
>>> + return;
>>> + }
>>> +
>>> + cxl_dport_init_ras_reporting(parent_dport, cxlmd->cxlds->dev);
>>> +}
>>> +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>>> +
>>> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>>> {
>>> void __iomem *addr;
>>> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
>>> index 259ed4b676e1..b7654d40dc9e 100644
>>> --- a/drivers/cxl/cxl.h
>>> +++ b/drivers/cxl/cxl.h
>>> @@ -599,6 +599,7 @@ struct cxl_dax_region {
>>> * @parent_dport: dport that points to this port in the parent
>>> * @decoder_ida: allocator for decoder ids
>>> * @reg_map: component and ras register mapping parameters
>>> + * @uport_regs: mapped component registers
>>> * @nr_dports: number of entries in @dports
>>> * @hdm_end: track last allocated HDM decoder instance for allocation ordering
>>> * @commit_end: cursor to track highest committed decoder for commit ordering
>>> @@ -620,6 +621,7 @@ struct cxl_port {
>>> struct cxl_dport *parent_dport;
>>> struct ida decoder_ida;
>>> struct cxl_register_map reg_map;
>>> + struct cxl_component_regs uport_regs;
>>> int nr_dports;
>>> int hdm_end;
>>> int commit_end;
>>> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
>>> index 0c8b6ee7b6de..3882a089ae77 100644
>>> --- a/drivers/cxl/cxlpci.h
>>> +++ b/drivers/cxl/cxlpci.h
>>> @@ -82,7 +82,6 @@ void read_cdat_data(struct cxl_port *port);
>>> void cxl_cor_error_detected(struct pci_dev *pdev);
>>> pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>>> pci_channel_state_t state);
>>> -void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>>> #else
>>> static inline void cxl_cor_error_detected(struct pci_dev *pdev) { }
>>> @@ -91,9 +90,6 @@ static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>>> {
>>> return PCI_ERS_RESULT_NONE;
>>> }
>>> -
>>> -static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>>> - struct device *host) { }
>>> #endif
>>> #endif /* __CXL_PCI_H__ */
>> I think this change broke cxl_test:
>>
>> CC [M] test/mem.o
>> test/mock.c: In function ‘__wrap_cxl_dport_init_ras_reporting’:
>> test/mock.c:266:17: error: implicit declaration of function ‘cxl_dport_init_ras_reporting’ [-Wimplicit-function-declaration]
>> 266 | cxl_dport_init_ras_reporting(dport, host);
>> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>
>>
>>> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
>>> index 6e6777b7bafb..f7dc0ba8905d 100644
>>> --- a/drivers/cxl/mem.c
>>> +++ b/drivers/cxl/mem.c
>>> @@ -7,6 +7,7 @@
>>> #include "cxlmem.h"
>>> #include "cxlpci.h"
>>> +#include "core/core.h"
>>> /**
>>> * DOC: cxl mem
>>> @@ -166,7 +167,8 @@ static int cxl_mem_probe(struct device *dev)
>>> else
>>> endpoint_parent = &parent_port->dev;
>>> - cxl_dport_init_ras_reporting(dport, dev);
>>> + if (dport->rch)
>>> + cxl_dport_init_ras_reporting(dport, dev);
>>> scoped_guard(device, endpoint_parent) {
>>> if (!endpoint_parent->driver) {
>>> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
>>> index 51c8f2f84717..2d12890b66fe 100644
>>> --- a/drivers/cxl/port.c
>>> +++ b/drivers/cxl/port.c
>>> @@ -6,6 +6,7 @@
>>> #include "cxlmem.h"
>>> #include "cxlpci.h"
>>> +#include "core/core.h"
>>> /**
>>> * DOC: cxl port
>>> @@ -65,6 +66,8 @@ static int cxl_switch_port_probe(struct cxl_port *port)
>>> /* Cache the data early to ensure is_visible() works */
>>> read_cdat_data(port);
>>> + cxl_switch_port_init_ras(port);
>> This is probably not the right place to do it because you have no dports yet with the new delayed dport setup. I would init the uport when the register gets probed in __devm_cxl_add_dport(), and init the dport on per dport basis as they are discovered. So maybe in cxl_port_add_dport(). This is where the old dport stuff in the switch probe got moved to.
>>
>>> +
>>> return 0;
>>> }
>>> @@ -86,6 +89,8 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
>>> if (rc)
>>> return rc;
>>> + cxl_endpoint_port_init_ras(port);
>>> +
>>> /*
>>> * Now that all endpoint decoders are successfully enumerated, try to
>>> * assemble regions from committed decoders
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 15/25] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
2025-10-24 10:25 ` Alejandro Lucero Palau
2025-10-24 17:15 ` Dave Jiang
@ 2025-10-24 19:40 ` Bowman, Terry
2025-10-27 16:33 ` Alejandro Lucero Palau
1 sibling, 1 reply; 92+ messages in thread
From: Bowman, Terry @ 2025-10-24 19:40 UTC (permalink / raw)
To: Alejandro Lucero Palau, Dave Jiang, dave, jonathan.cameron,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, ira.weiny
Cc: linux-kernel, linux-pci
On 10/24/2025 5:25 AM, Alejandro Lucero Palau wrote:
> On 9/26/25 22:10, Dave Jiang wrote:
>> On 9/25/25 3:34 PM, Terry Bowman wrote:
>>> CXL Endpoint (EP) Ports may include Root Ports (RP) or Downstream Switch
>>> Ports (DSP). CXL RPs and DSPs contain RAS registers that require memory
>>> mapping to enable RAS logging. This initialization is currently missing and
>>> must be added for CXL RPs and DSPs.
>>>
>>> Update cxl_dport_init_ras_reporting() to support RP and DSP RAS mapping.
>>> Add alongside the existing Restricted CXL Host Downstream Port RAS mapping.
>>>
>>> Update cxl_endpoint_port_probe() to invoke cxl_dport_init_ras_reporting().
>>> This will initiate the RAS mapping for CXL RPs and DSPs when each CXL EP is
>>> created and added to the EP port.
>>>
>>> Make a call to cxl_port_setup_regs() in cxl_port_add(). This will probe the
>>> Upstream Port's CXL capabilities' physical location to be used in mapping
>>> the RAS registers.
>>>
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>>
>>> ---
>>>
>>> Changes in v11->v12:
>>> - Add check for dport_parent->rch before calling cxl_dport_init_ras_reporting().
>>> RCH dports are initialized from cxl_dport_init_ras_reporting cxl_mem_probe().
>>>
>>> Changes in v10->v11:
>>> - Use local pointer for readability in cxl_switch_port_init_ras() (Jonathan Cameron)
>>> - Rename port to be ep in cxl_endpoint_port_init_ras() (Dave Jiang)
>>> - Rename dport to be parent_dport in cxl_endpoint_port_init_ras()
>>> and cxl_switch_port_init_ras() (Dave Jiang)
>>> - Port helper changes were in cxl/port.c, now in core/ras.c (Dave
>>> Jiang)
>>> ---
>>> drivers/cxl/core/core.h | 7 ++++++
>>> drivers/cxl/core/port.c | 1 +
>>> drivers/cxl/core/ras.c | 48 +++++++++++++++++++++++++++++++++++++++++
>>> drivers/cxl/cxl.h | 2 ++
>>> drivers/cxl/cxlpci.h | 4 ----
>>> drivers/cxl/mem.c | 4 +++-
>>> drivers/cxl/port.c | 5 +++++
>>> 7 files changed, 66 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
>>> index 9f4eb7e2feba..8c51a2631716 100644
>>> --- a/drivers/cxl/core/core.h
>>> +++ b/drivers/cxl/core/core.h
>>> @@ -147,6 +147,9 @@ int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
>>> #ifdef CONFIG_CXL_RAS
>>> int cxl_ras_init(void);
>>> void cxl_ras_exit(void);
>>> +void cxl_switch_port_init_ras(struct cxl_port *port);
>>> +void cxl_endpoint_port_init_ras(struct cxl_port *ep);
>>> +void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>>> #else
>>> static inline int cxl_ras_init(void)
>>> {
>>> @@ -156,6 +159,10 @@ static inline int cxl_ras_init(void)
>>> static inline void cxl_ras_exit(void)
>>> {
>>> }
>>> +static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
>>> +static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
>>> +static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>>> + struct device *host) { }
>>> #endif // CONFIG_CXL_RAS
>>>
>>> int cxl_gpf_port_setup(struct cxl_dport *dport);
>>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>>> index d5f71eb1ade8..bd4be046888a 100644
>>> --- a/drivers/cxl/core/port.c
>>> +++ b/drivers/cxl/core/port.c
>>> @@ -870,6 +870,7 @@ static int cxl_port_add(struct cxl_port *port,
>>> return rc;
>>>
>>> port->component_reg_phys = component_reg_phys;
>>> + cxl_port_setup_regs(port, port->component_reg_phys);
>> This was actually moved previously to delay the port register probe. It now happens when the first dport is discovered. See the end of __devm_cxl_add_dport().
>
> FWIW (other people not going through my discovery path :-) ) Dave is
> pointing out to his patchset for delaying port probing and now applied
> to next.
>
>
> Terry, any estimation of when your next version will be sent to the
> list? My Type2 patchset is dependent on yours, so I'll be reviewing it
> as soon as you do it.
>
>
> Thank you
>
Hi Alejandro,
It will be early next week.
Terry
>>> } else {
>>> rc = dev_set_name(dev, "root%d", port->id);
>>> if (rc)
>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>> index 97a5a5c3910f..14a434bd68f0 100644
>>> --- a/drivers/cxl/core/ras.c
>>> +++ b/drivers/cxl/core/ras.c
>>> @@ -283,6 +283,54 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
>>> }
>>> EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
>>>
>>> +static void cxl_uport_init_ras_reporting(struct cxl_port *port,
>>> + struct device *host)
>>> +{
>>> + struct cxl_register_map *map = &port->reg_map;
>>> +
>>> + map->host = host;
>>> + if (cxl_map_component_regs(map, &port->uport_regs,
>>> + BIT(CXL_CM_CAP_CAP_ID_RAS)))
>>> + dev_dbg(&port->dev, "Failed to map RAS capability\n");
>>> +}
>>> +
>>> +void cxl_switch_port_init_ras(struct cxl_port *port)
>>> +{
>>> + struct cxl_dport *parent_dport = port->parent_dport;
>>> +
>>> + if (is_cxl_root(to_cxl_port(port->dev.parent)))
>>> + return;
>>> +
>>> + /* May have parent DSP or RP */
>>> + if (parent_dport && dev_is_pci(parent_dport->dport_dev) &&
>>> + !parent_dport->rch) {
>>> + struct pci_dev *pdev = to_pci_dev(parent_dport->dport_dev);
>>> +
>>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM))
>>> + cxl_dport_init_ras_reporting(parent_dport, &port->dev);
>>> + }
>>> +
>>> + cxl_uport_init_ras_reporting(port, &port->dev);
>>> +}
>>> +EXPORT_SYMBOL_NS_GPL(cxl_switch_port_init_ras, "CXL");
>>> +
>>> +void cxl_endpoint_port_init_ras(struct cxl_port *ep)
>>> +{
>>> + struct cxl_dport *parent_dport;
>>> + struct cxl_memdev *cxlmd = to_cxl_memdev(ep->uport_dev);
>>> + struct cxl_port *parent_port __free(put_cxl_port) =
>>> + cxl_mem_find_port(cxlmd, &parent_dport);
>>> +
>>> + if (!parent_dport || !dev_is_pci(parent_dport->dport_dev) || parent_dport->rch) {
>>> + dev_err(&ep->dev, "CXL port topology not found\n");
>>> + return;
>>> + }
>>> +
>>> + cxl_dport_init_ras_reporting(parent_dport, cxlmd->cxlds->dev);
>>> +}
>>> +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>>> +
>>> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>>> {
>>> void __iomem *addr;
>>> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
>>> index 259ed4b676e1..b7654d40dc9e 100644
>>> --- a/drivers/cxl/cxl.h
>>> +++ b/drivers/cxl/cxl.h
>>> @@ -599,6 +599,7 @@ struct cxl_dax_region {
>>> * @parent_dport: dport that points to this port in the parent
>>> * @decoder_ida: allocator for decoder ids
>>> * @reg_map: component and ras register mapping parameters
>>> + * @uport_regs: mapped component registers
>>> * @nr_dports: number of entries in @dports
>>> * @hdm_end: track last allocated HDM decoder instance for allocation ordering
>>> * @commit_end: cursor to track highest committed decoder for commit ordering
>>> @@ -620,6 +621,7 @@ struct cxl_port {
>>> struct cxl_dport *parent_dport;
>>> struct ida decoder_ida;
>>> struct cxl_register_map reg_map;
>>> + struct cxl_component_regs uport_regs;
>>> int nr_dports;
>>> int hdm_end;
>>> int commit_end;
>>> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
>>> index 0c8b6ee7b6de..3882a089ae77 100644
>>> --- a/drivers/cxl/cxlpci.h
>>> +++ b/drivers/cxl/cxlpci.h
>>> @@ -82,7 +82,6 @@ void read_cdat_data(struct cxl_port *port);
>>> void cxl_cor_error_detected(struct pci_dev *pdev);
>>> pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>>> pci_channel_state_t state);
>>> -void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>>> #else
>>> static inline void cxl_cor_error_detected(struct pci_dev *pdev) { }
>>>
>>> @@ -91,9 +90,6 @@ static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>>> {
>>> return PCI_ERS_RESULT_NONE;
>>> }
>>> -
>>> -static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>>> - struct device *host) { }
>>> #endif
>>>
>>> #endif /* __CXL_PCI_H__ */
>> I think this change broke cxl_test:
>>
>> CC [M] test/mem.o
>> test/mock.c: In function ‘__wrap_cxl_dport_init_ras_reporting’:
>> test/mock.c:266:17: error: implicit declaration of function ‘cxl_dport_init_ras_reporting’ [-Wimplicit-function-declaration]
>> 266 | cxl_dport_init_ras_reporting(dport, host);
>> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>
>>
>>> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
>>> index 6e6777b7bafb..f7dc0ba8905d 100644
>>> --- a/drivers/cxl/mem.c
>>> +++ b/drivers/cxl/mem.c
>>> @@ -7,6 +7,7 @@
>>>
>>> #include "cxlmem.h"
>>> #include "cxlpci.h"
>>> +#include "core/core.h"
>>>
>>> /**
>>> * DOC: cxl mem
>>> @@ -166,7 +167,8 @@ static int cxl_mem_probe(struct device *dev)
>>> else
>>> endpoint_parent = &parent_port->dev;
>>>
>>> - cxl_dport_init_ras_reporting(dport, dev);
>>> + if (dport->rch)
>>> + cxl_dport_init_ras_reporting(dport, dev);
>>>
>>> scoped_guard(device, endpoint_parent) {
>>> if (!endpoint_parent->driver) {
>>> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
>>> index 51c8f2f84717..2d12890b66fe 100644
>>> --- a/drivers/cxl/port.c
>>> +++ b/drivers/cxl/port.c
>>> @@ -6,6 +6,7 @@
>>>
>>> #include "cxlmem.h"
>>> #include "cxlpci.h"
>>> +#include "core/core.h"
>>>
>>> /**
>>> * DOC: cxl port
>>> @@ -65,6 +66,8 @@ static int cxl_switch_port_probe(struct cxl_port *port)
>>> /* Cache the data early to ensure is_visible() works */
>>> read_cdat_data(port);
>>>
>>> + cxl_switch_port_init_ras(port);
>> This is probably not the right place to do it because you have no dports yet with the new delayed dport setup. I would init the uport when the register gets probed in __devm_cxl_add_dport(), and init the dport on per dport basis as they are discovered. So maybe in cxl_port_add_dport(). This is where the old dport stuff in the switch probe got moved to.
>>
>>> +
>>> return 0;
>>> }
>>>
>>> @@ -86,6 +89,8 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
>>> if (rc)
>>> return rc;
>>>
>>> + cxl_endpoint_port_init_ras(port);
>>> +
>>> /*
>>> * Now that all endpoint decoders are successfully enumerated, try to
>>> * assemble regions from committed decoders
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 15/25] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
2025-10-24 19:40 ` Bowman, Terry
@ 2025-10-27 16:33 ` Alejandro Lucero Palau
0 siblings, 0 replies; 92+ messages in thread
From: Alejandro Lucero Palau @ 2025-10-27 16:33 UTC (permalink / raw)
To: Bowman, Terry, Dave Jiang, dave, jonathan.cameron,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, ira.weiny
Cc: linux-kernel, linux-pci
On 10/24/25 20:40, Bowman, Terry wrote:
>
> On 10/24/2025 5:25 AM, Alejandro Lucero Palau wrote:
>> On 9/26/25 22:10, Dave Jiang wrote:
>>> On 9/25/25 3:34 PM, Terry Bowman wrote:
>>>> CXL Endpoint (EP) Ports may include Root Ports (RP) or Downstream Switch
>>>> Ports (DSP). CXL RPs and DSPs contain RAS registers that require memory
>>>> mapping to enable RAS logging. This initialization is currently missing and
>>>> must be added for CXL RPs and DSPs.
>>>>
>>>> Update cxl_dport_init_ras_reporting() to support RP and DSP RAS mapping.
>>>> Add alongside the existing Restricted CXL Host Downstream Port RAS mapping.
>>>>
>>>> Update cxl_endpoint_port_probe() to invoke cxl_dport_init_ras_reporting().
>>>> This will initiate the RAS mapping for CXL RPs and DSPs when each CXL EP is
>>>> created and added to the EP port.
>>>>
>>>> Make a call to cxl_port_setup_regs() in cxl_port_add(). This will probe the
>>>> Upstream Port's CXL capabilities' physical location to be used in mapping
>>>> the RAS registers.
>>>>
>>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>>>
>>>> ---
>>>>
>>>> Changes in v11->v12:
>>>> - Add check for dport_parent->rch before calling cxl_dport_init_ras_reporting().
>>>> RCH dports are initialized from cxl_dport_init_ras_reporting cxl_mem_probe().
>>>>
>>>> Changes in v10->v11:
>>>> - Use local pointer for readability in cxl_switch_port_init_ras() (Jonathan Cameron)
>>>> - Rename port to be ep in cxl_endpoint_port_init_ras() (Dave Jiang)
>>>> - Rename dport to be parent_dport in cxl_endpoint_port_init_ras()
>>>> and cxl_switch_port_init_ras() (Dave Jiang)
>>>> - Port helper changes were in cxl/port.c, now in core/ras.c (Dave
>>>> Jiang)
>>>> ---
>>>> drivers/cxl/core/core.h | 7 ++++++
>>>> drivers/cxl/core/port.c | 1 +
>>>> drivers/cxl/core/ras.c | 48 +++++++++++++++++++++++++++++++++++++++++
>>>> drivers/cxl/cxl.h | 2 ++
>>>> drivers/cxl/cxlpci.h | 4 ----
>>>> drivers/cxl/mem.c | 4 +++-
>>>> drivers/cxl/port.c | 5 +++++
>>>> 7 files changed, 66 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
>>>> index 9f4eb7e2feba..8c51a2631716 100644
>>>> --- a/drivers/cxl/core/core.h
>>>> +++ b/drivers/cxl/core/core.h
>>>> @@ -147,6 +147,9 @@ int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
>>>> #ifdef CONFIG_CXL_RAS
>>>> int cxl_ras_init(void);
>>>> void cxl_ras_exit(void);
>>>> +void cxl_switch_port_init_ras(struct cxl_port *port);
>>>> +void cxl_endpoint_port_init_ras(struct cxl_port *ep);
>>>> +void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>>>> #else
>>>> static inline int cxl_ras_init(void)
>>>> {
>>>> @@ -156,6 +159,10 @@ static inline int cxl_ras_init(void)
>>>> static inline void cxl_ras_exit(void)
>>>> {
>>>> }
>>>> +static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
>>>> +static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
>>>> +static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>>>> + struct device *host) { }
>>>> #endif // CONFIG_CXL_RAS
>>>>
>>>> int cxl_gpf_port_setup(struct cxl_dport *dport);
>>>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>>>> index d5f71eb1ade8..bd4be046888a 100644
>>>> --- a/drivers/cxl/core/port.c
>>>> +++ b/drivers/cxl/core/port.c
>>>> @@ -870,6 +870,7 @@ static int cxl_port_add(struct cxl_port *port,
>>>> return rc;
>>>>
>>>> port->component_reg_phys = component_reg_phys;
>>>> + cxl_port_setup_regs(port, port->component_reg_phys);
>>> This was actually moved previously to delay the port register probe. It now happens when the first dport is discovered. See the end of __devm_cxl_add_dport().
>> FWIW (other people not going through my discovery path :-) ) Dave is
>> pointing out to his patchset for delaying port probing and now applied
>> to next.
>>
>>
>> Terry, any estimation of when your next version will be sent to the
>> list? My Type2 patchset is dependent on yours, so I'll be reviewing it
>> as soon as you do it.
>>
>>
>> Thank you
>>
> Hi Alejandro,
>
> It will be early next week.
>
> Terry
Great.
Maybe it would be worth to consider if your patch 8, the one Type2
support now relies on, could be applied along with Type2 work if that
dependency ends up being the only thing remaining, and with your
patchset requiring more cycles. I will raise this tomorrow, after
knowing what Dan thinks about type2 patchset state.
Thank you
>>>> } else {
>>>> rc = dev_set_name(dev, "root%d", port->id);
>>>> if (rc)
>>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>>> index 97a5a5c3910f..14a434bd68f0 100644
>>>> --- a/drivers/cxl/core/ras.c
>>>> +++ b/drivers/cxl/core/ras.c
>>>> @@ -283,6 +283,54 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
>>>> }
>>>> EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
>>>>
>>>> +static void cxl_uport_init_ras_reporting(struct cxl_port *port,
>>>> + struct device *host)
>>>> +{
>>>> + struct cxl_register_map *map = &port->reg_map;
>>>> +
>>>> + map->host = host;
>>>> + if (cxl_map_component_regs(map, &port->uport_regs,
>>>> + BIT(CXL_CM_CAP_CAP_ID_RAS)))
>>>> + dev_dbg(&port->dev, "Failed to map RAS capability\n");
>>>> +}
>>>> +
>>>> +void cxl_switch_port_init_ras(struct cxl_port *port)
>>>> +{
>>>> + struct cxl_dport *parent_dport = port->parent_dport;
>>>> +
>>>> + if (is_cxl_root(to_cxl_port(port->dev.parent)))
>>>> + return;
>>>> +
>>>> + /* May have parent DSP or RP */
>>>> + if (parent_dport && dev_is_pci(parent_dport->dport_dev) &&
>>>> + !parent_dport->rch) {
>>>> + struct pci_dev *pdev = to_pci_dev(parent_dport->dport_dev);
>>>> +
>>>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
>>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM))
>>>> + cxl_dport_init_ras_reporting(parent_dport, &port->dev);
>>>> + }
>>>> +
>>>> + cxl_uport_init_ras_reporting(port, &port->dev);
>>>> +}
>>>> +EXPORT_SYMBOL_NS_GPL(cxl_switch_port_init_ras, "CXL");
>>>> +
>>>> +void cxl_endpoint_port_init_ras(struct cxl_port *ep)
>>>> +{
>>>> + struct cxl_dport *parent_dport;
>>>> + struct cxl_memdev *cxlmd = to_cxl_memdev(ep->uport_dev);
>>>> + struct cxl_port *parent_port __free(put_cxl_port) =
>>>> + cxl_mem_find_port(cxlmd, &parent_dport);
>>>> +
>>>> + if (!parent_dport || !dev_is_pci(parent_dport->dport_dev) || parent_dport->rch) {
>>>> + dev_err(&ep->dev, "CXL port topology not found\n");
>>>> + return;
>>>> + }
>>>> +
>>>> + cxl_dport_init_ras_reporting(parent_dport, cxlmd->cxlds->dev);
>>>> +}
>>>> +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>>>> +
>>>> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>>>> {
>>>> void __iomem *addr;
>>>> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
>>>> index 259ed4b676e1..b7654d40dc9e 100644
>>>> --- a/drivers/cxl/cxl.h
>>>> +++ b/drivers/cxl/cxl.h
>>>> @@ -599,6 +599,7 @@ struct cxl_dax_region {
>>>> * @parent_dport: dport that points to this port in the parent
>>>> * @decoder_ida: allocator for decoder ids
>>>> * @reg_map: component and ras register mapping parameters
>>>> + * @uport_regs: mapped component registers
>>>> * @nr_dports: number of entries in @dports
>>>> * @hdm_end: track last allocated HDM decoder instance for allocation ordering
>>>> * @commit_end: cursor to track highest committed decoder for commit ordering
>>>> @@ -620,6 +621,7 @@ struct cxl_port {
>>>> struct cxl_dport *parent_dport;
>>>> struct ida decoder_ida;
>>>> struct cxl_register_map reg_map;
>>>> + struct cxl_component_regs uport_regs;
>>>> int nr_dports;
>>>> int hdm_end;
>>>> int commit_end;
>>>> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
>>>> index 0c8b6ee7b6de..3882a089ae77 100644
>>>> --- a/drivers/cxl/cxlpci.h
>>>> +++ b/drivers/cxl/cxlpci.h
>>>> @@ -82,7 +82,6 @@ void read_cdat_data(struct cxl_port *port);
>>>> void cxl_cor_error_detected(struct pci_dev *pdev);
>>>> pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>>>> pci_channel_state_t state);
>>>> -void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>>>> #else
>>>> static inline void cxl_cor_error_detected(struct pci_dev *pdev) { }
>>>>
>>>> @@ -91,9 +90,6 @@ static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>>>> {
>>>> return PCI_ERS_RESULT_NONE;
>>>> }
>>>> -
>>>> -static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>>>> - struct device *host) { }
>>>> #endif
>>>>
>>>> #endif /* __CXL_PCI_H__ */
>>> I think this change broke cxl_test:
>>>
>>> CC [M] test/mem.o
>>> test/mock.c: In function ‘__wrap_cxl_dport_init_ras_reporting’:
>>> test/mock.c:266:17: error: implicit declaration of function ‘cxl_dport_init_ras_reporting’ [-Wimplicit-function-declaration]
>>> 266 | cxl_dport_init_ras_reporting(dport, host);
>>> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>
>>>
>>>> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
>>>> index 6e6777b7bafb..f7dc0ba8905d 100644
>>>> --- a/drivers/cxl/mem.c
>>>> +++ b/drivers/cxl/mem.c
>>>> @@ -7,6 +7,7 @@
>>>>
>>>> #include "cxlmem.h"
>>>> #include "cxlpci.h"
>>>> +#include "core/core.h"
>>>>
>>>> /**
>>>> * DOC: cxl mem
>>>> @@ -166,7 +167,8 @@ static int cxl_mem_probe(struct device *dev)
>>>> else
>>>> endpoint_parent = &parent_port->dev;
>>>>
>>>> - cxl_dport_init_ras_reporting(dport, dev);
>>>> + if (dport->rch)
>>>> + cxl_dport_init_ras_reporting(dport, dev);
>>>>
>>>> scoped_guard(device, endpoint_parent) {
>>>> if (!endpoint_parent->driver) {
>>>> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
>>>> index 51c8f2f84717..2d12890b66fe 100644
>>>> --- a/drivers/cxl/port.c
>>>> +++ b/drivers/cxl/port.c
>>>> @@ -6,6 +6,7 @@
>>>>
>>>> #include "cxlmem.h"
>>>> #include "cxlpci.h"
>>>> +#include "core/core.h"
>>>>
>>>> /**
>>>> * DOC: cxl port
>>>> @@ -65,6 +66,8 @@ static int cxl_switch_port_probe(struct cxl_port *port)
>>>> /* Cache the data early to ensure is_visible() works */
>>>> read_cdat_data(port);
>>>>
>>>> + cxl_switch_port_init_ras(port);
>>> This is probably not the right place to do it because you have no dports yet with the new delayed dport setup. I would init the uport when the register gets probed in __devm_cxl_add_dport(), and init the dport on per dport basis as they are discovered. So maybe in cxl_port_add_dport(). This is where the old dport stuff in the switch probe got moved to.
>>>
>>>> +
>>>> return 0;
>>>> }
>>>>
>>>> @@ -86,6 +89,8 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
>>>> if (rc)
>>>> return rc;
>>>>
>>>> + cxl_endpoint_port_init_ras(port);
>>>> +
>>>> /*
>>>> * Now that all endpoint decoders are successfully enumerated, try to
>>>> * assemble regions from committed decoders
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 16/25] CXL/PCI: Introduce PCI_ERS_RESULT_PANIC
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (14 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 15/25] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-26 21:26 ` Dave Jiang
` (2 more replies)
2025-09-25 22:34 ` [PATCH v12 17/25] cxl/pci: Introduce CXL Endpoint protocol error handlers Terry Bowman
` (8 subsequent siblings)
24 siblings, 3 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
The CXL driver's error handling for uncorrectable errors (UCE) will be
updated in the future. A required change is for the error handlers to
to force a system panic when a UCE is detected.
Introduce PCI_ERS_RESULT_PANIC as a 'enum pci_ers_result' type. This will
be used by CXL UCE fatal and non-fatal recovery in future patches. Update
PCIe recovery documentation with details of PCI_ERS_RESULT_PANIC.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
Changes v11 -> v12:
- Documentation requested by (Lukas)
---
Documentation/PCI/pci-error-recovery.rst | 6 ++++++
include/linux/pci.h | 3 +++
2 files changed, 9 insertions(+)
diff --git a/Documentation/PCI/pci-error-recovery.rst b/Documentation/PCI/pci-error-recovery.rst
index 42e1e78353f3..f823a6c1fb23 100644
--- a/Documentation/PCI/pci-error-recovery.rst
+++ b/Documentation/PCI/pci-error-recovery.rst
@@ -102,6 +102,8 @@ Possible return values are::
PCI_ERS_RESULT_NEED_RESET, /* Device driver wants slot to be reset. */
PCI_ERS_RESULT_DISCONNECT, /* Device has completely failed, is unrecoverable */
PCI_ERS_RESULT_RECOVERED, /* Device driver is fully recovered and operational */
+ PCI_ERS_RESULT_NO_AER_DRIVER, /* No AER capabilities registered for the driver */
+ PCI_ERS_RESULT_PANIC, /* System is unstable, panic. Is CXL specific */
};
A driver does not have to implement all of these callbacks; however,
@@ -116,6 +118,10 @@ The actual steps taken by a platform to recover from a PCI error
event will be platform-dependent, but will follow the general
sequence described below.
+PCI_ERS_RESULT_PANIC is currently unique to CXL and handled in CXL
+cxl_do_recdovery(). The PCI pcie_do_recovery() routine does not report or
+handle PCI_ERS_RESULT_PANIC.
+
STEP 0: Error Event
-------------------
A PCI bus error is detected by the PCI hardware. On powerpc, the slot
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 53a45e92c635..bc3a7b6d0f94 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -889,6 +889,9 @@ enum pci_ers_result {
/* No AER capabilities registered for the driver */
PCI_ERS_RESULT_NO_AER_DRIVER = (__force pci_ers_result_t) 6,
+
+ /* System is unstable, panic. Is CXL specific */
+ PCI_ERS_RESULT_PANIC = (__force pci_ers_result_t) 7,
};
/* PCI bus error event callbacks */
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 16/25] CXL/PCI: Introduce PCI_ERS_RESULT_PANIC
2025-09-25 22:34 ` [PATCH v12 16/25] CXL/PCI: Introduce PCI_ERS_RESULT_PANIC Terry Bowman
@ 2025-09-26 21:26 ` Dave Jiang
2025-10-01 16:14 ` Jonathan Cameron
2025-10-03 20:11 ` Cheatham, Benjamin
2 siblings, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-26 21:26 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> The CXL driver's error handling for uncorrectable errors (UCE) will be
> updated in the future. A required change is for the error handlers to
> to force a system panic when a UCE is detected.
>
> Introduce PCI_ERS_RESULT_PANIC as a 'enum pci_ers_result' type. This will
> be used by CXL UCE fatal and non-fatal recovery in future patches. Update
> PCIe recovery documentation with details of PCI_ERS_RESULT_PANIC.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> ---
>
> Changes v11 -> v12:
> - Documentation requested by (Lukas)
> ---
> Documentation/PCI/pci-error-recovery.rst | 6 ++++++
> include/linux/pci.h | 3 +++
> 2 files changed, 9 insertions(+)
>
> diff --git a/Documentation/PCI/pci-error-recovery.rst b/Documentation/PCI/pci-error-recovery.rst
> index 42e1e78353f3..f823a6c1fb23 100644
> --- a/Documentation/PCI/pci-error-recovery.rst
> +++ b/Documentation/PCI/pci-error-recovery.rst
> @@ -102,6 +102,8 @@ Possible return values are::
> PCI_ERS_RESULT_NEED_RESET, /* Device driver wants slot to be reset. */
> PCI_ERS_RESULT_DISCONNECT, /* Device has completely failed, is unrecoverable */
> PCI_ERS_RESULT_RECOVERED, /* Device driver is fully recovered and operational */
> + PCI_ERS_RESULT_NO_AER_DRIVER, /* No AER capabilities registered for the driver */
> + PCI_ERS_RESULT_PANIC, /* System is unstable, panic. Is CXL specific */
> };
>
> A driver does not have to implement all of these callbacks; however,
> @@ -116,6 +118,10 @@ The actual steps taken by a platform to recover from a PCI error
> event will be platform-dependent, but will follow the general
> sequence described below.
>
> +PCI_ERS_RESULT_PANIC is currently unique to CXL and handled in CXL
> +cxl_do_recdovery(). The PCI pcie_do_recovery() routine does not report or
> +handle PCI_ERS_RESULT_PANIC.
> +
> STEP 0: Error Event
> -------------------
> A PCI bus error is detected by the PCI hardware. On powerpc, the slot
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 53a45e92c635..bc3a7b6d0f94 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -889,6 +889,9 @@ enum pci_ers_result {
>
> /* No AER capabilities registered for the driver */
> PCI_ERS_RESULT_NO_AER_DRIVER = (__force pci_ers_result_t) 6,
> +
> + /* System is unstable, panic. Is CXL specific */
> + PCI_ERS_RESULT_PANIC = (__force pci_ers_result_t) 7,
> };
>
> /* PCI bus error event callbacks */
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 16/25] CXL/PCI: Introduce PCI_ERS_RESULT_PANIC
2025-09-25 22:34 ` [PATCH v12 16/25] CXL/PCI: Introduce PCI_ERS_RESULT_PANIC Terry Bowman
2025-09-26 21:26 ` Dave Jiang
@ 2025-10-01 16:14 ` Jonathan Cameron
2025-10-03 20:11 ` Cheatham, Benjamin
2 siblings, 0 replies; 92+ messages in thread
From: Jonathan Cameron @ 2025-10-01 16:14 UTC (permalink / raw)
To: Terry Bowman
Cc: dave, dave.jiang, alison.schofield, dan.j.williams, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, linux-cxl,
alucerop, ira.weiny, linux-kernel, linux-pci
On Thu, 25 Sep 2025 17:34:31 -0500
Terry Bowman <terry.bowman@amd.com> wrote:
> The CXL driver's error handling for uncorrectable errors (UCE) will be
> updated in the future. A required change is for the error handlers to
> to force a system panic when a UCE is detected.
>
> Introduce PCI_ERS_RESULT_PANIC as a 'enum pci_ers_result' type. This will
> be used by CXL UCE fatal and non-fatal recovery in future patches. Update
> PCIe recovery documentation with details of PCI_ERS_RESULT_PANIC.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 16/25] CXL/PCI: Introduce PCI_ERS_RESULT_PANIC
2025-09-25 22:34 ` [PATCH v12 16/25] CXL/PCI: Introduce PCI_ERS_RESULT_PANIC Terry Bowman
2025-09-26 21:26 ` Dave Jiang
2025-10-01 16:14 ` Jonathan Cameron
@ 2025-10-03 20:11 ` Cheatham, Benjamin
2 siblings, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:11 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> The CXL driver's error handling for uncorrectable errors (UCE) will be
> updated in the future. A required change is for the error handlers to
> to force a system panic when a UCE is detected.
>
> Introduce PCI_ERS_RESULT_PANIC as a 'enum pci_ers_result' type. This will
> be used by CXL UCE fatal and non-fatal recovery in future patches. Update
> PCIe recovery documentation with details of PCI_ERS_RESULT_PANIC.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>
> ---
>
> Changes v11 -> v12:
> - Documentation requested by (Lukas)
> ---
> Documentation/PCI/pci-error-recovery.rst | 6 ++++++
> include/linux/pci.h | 3 +++
> 2 files changed, 9 insertions(+)
>
> diff --git a/Documentation/PCI/pci-error-recovery.rst b/Documentation/PCI/pci-error-recovery.rst
> index 42e1e78353f3..f823a6c1fb23 100644
> --- a/Documentation/PCI/pci-error-recovery.rst
> +++ b/Documentation/PCI/pci-error-recovery.rst
> @@ -102,6 +102,8 @@ Possible return values are::
> PCI_ERS_RESULT_NEED_RESET, /* Device driver wants slot to be reset. */
> PCI_ERS_RESULT_DISCONNECT, /* Device has completely failed, is unrecoverable */
> PCI_ERS_RESULT_RECOVERED, /* Device driver is fully recovered and operational */
> + PCI_ERS_RESULT_NO_AER_DRIVER, /* No AER capabilities registered for the driver */
> + PCI_ERS_RESULT_PANIC, /* System is unstable, panic. Is CXL specific */
> };
>
> A driver does not have to implement all of these callbacks; however,
> @@ -116,6 +118,10 @@ The actual steps taken by a platform to recover from a PCI error
> event will be platform-dependent, but will follow the general
> sequence described below.
>
> +PCI_ERS_RESULT_PANIC is currently unique to CXL and handled in CXL
> +cxl_do_recdovery(). The PCI pcie_do_recovery() routine does not report or
s/recdovery/recovery
With that:
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 17/25] cxl/pci: Introduce CXL Endpoint protocol error handlers
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (15 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 16/25] CXL/PCI: Introduce PCI_ERS_RESULT_PANIC Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-26 22:04 ` Dave Jiang
2025-10-03 20:12 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 18/25] CXL/AER: Introduce aer_cxl_vh.c in AER driver for forwarding CXL errors Terry Bowman
` (7 subsequent siblings)
24 siblings, 2 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
CXL Endpoint protocol errors are currently handled using PCI error
handlers. The CXL Endpoint requires CXL specific handling in the case of
uncorrectable error (UCE) handling not provided by the PCI handlers.
Add CXL specific handlers for CXL Endpoints. Rename the existing
cxl_error_handlers to be pci_error_handlers to more correctly indicate
the error type and follow naming consistency.
The PCI handlers will be called if the CXL device is not trained for
alternate protocol (CXL). Update the CXL Endpoint PCI handlers to call the
CXL UCE handlers.
The existing EP UCE handler includes checks for various results. These are
no longer needed because CXL UCE recovery will not be attempted. Implement
cxl_handle_ras() to return PCI_ERS_RESULT_NONE or PCI_ERS_RESULT_PANIC. The
CXL UCE handler is called by cxl_do_recovery() that acts on the return
value. In the case of the PCI handler path, call panic() if the result is
PCI_ERS_RESULT_PANIC.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
Changes in v11->v12:
- None
Changes in v10->v11:
- cxl_error_detected() - Change handlers' scoped_guard() to guard() (Jonathan)
- cxl_error_detected() - Remove extra line (Shiju)
- Changes moved to core/ras.c (Terry)
- cxl_error_detected(), remove 'ue' and return with function call. (Jonathan)
- Remove extra space in documentation for PCI_ERS_RESULT_PANIC definition
- Move #include "pci.h from cxl.h to core.h (Terry)
- Remove unnecessary includes of cxl.h and core.h in mem.c (Terry)
---
drivers/cxl/core/core.h | 17 +++++++
drivers/cxl/core/ras.c | 110 +++++++++++++++++++---------------------
drivers/cxl/cxlpci.h | 15 ------
drivers/cxl/pci.c | 9 ++--
4 files changed, 75 insertions(+), 76 deletions(-)
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 8c51a2631716..74c64d458f12 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -6,6 +6,7 @@
#include <cxl/mailbox.h>
#include <linux/rwsem.h>
+#include <linux/pci.h>
extern const struct device_type cxl_nvdimm_bridge_type;
extern const struct device_type cxl_nvdimm_type;
@@ -150,6 +151,11 @@ void cxl_ras_exit(void);
void cxl_switch_port_init_ras(struct cxl_port *port);
void cxl_endpoint_port_init_ras(struct cxl_port *ep);
void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
+pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t error);
+void pci_cor_error_detected(struct pci_dev *pdev);
+void cxl_cor_error_detected(struct device *dev);
+pci_ers_result_t cxl_error_detected(struct device *dev);
#else
static inline int cxl_ras_init(void)
{
@@ -163,6 +169,17 @@ static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
struct device *host) { }
+static inline pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t error)
+{
+ return PCI_ERS_RESULT_NONE;
+}
+static inline void pci_cor_error_detected(struct pci_dev *pdev) { }
+static inline void cxl_cor_error_detected(struct device *dev) { }
+static inline pci_ers_result_t cxl_error_detected(struct device *dev)
+{
+ return PCI_ERS_RESULT_NONE;
+}
#endif // CONFIG_CXL_RAS
int cxl_gpf_port_setup(struct cxl_dport *dport);
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 14a434bd68f0..39472d82d586 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -129,7 +129,7 @@ void cxl_ras_exit(void)
}
static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base);
-static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
+static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
#ifdef CONFIG_CXL_RCH_RAS
static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
@@ -371,7 +371,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
* Log the state of the RAS status registers and prepare them to log the
* next error status. Return 1 if reset needed.
*/
-static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
+static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
{
u32 hl[CXL_HEADERLOG_SIZE_U32];
void __iomem *addr;
@@ -380,13 +380,13 @@ static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_bas
if (!ras_base) {
dev_warn_once(dev, "CXL RAS register block is not mapped");
- return false;
+ return PCI_ERS_RESULT_NONE;
}
addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
status = readl(addr);
if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
- return false;
+ return PCI_ERS_RESULT_NONE;
/* If multiple errors, log header points to first error from ctrl reg */
if (hweight32(status) > 1) {
@@ -403,76 +403,72 @@ static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_bas
trace_cxl_aer_uncorrectable_error(dev, status, fe, hl, serial);
writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
- return true;
+ return PCI_ERS_RESULT_PANIC;
}
-void cxl_cor_error_detected(struct pci_dev *pdev)
+void cxl_cor_error_detected(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
- struct device *dev = &cxlds->cxlmd->dev;
+ struct device *cxlmd_dev = &cxlds->cxlmd->dev;
- scoped_guard(device, dev) {
- if (!dev->driver) {
- dev_warn(&pdev->dev,
- "%s: memdev disabled, abort error handling\n",
- dev_name(dev));
- return;
- }
+ guard(device)(cxlmd_dev);
- if (cxlds->rcd)
- cxl_handle_rdport_errors(cxlds);
-
- cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
+ if (!cxlmd_dev->driver) {
+ dev_warn(&pdev->dev, "%s: memdev disabled, abort error handling", dev_name(dev));
+ return;
}
+
+ if (cxlds->rcd)
+ cxl_handle_rdport_errors(cxlds);
+
+ cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
}
EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
-pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
- pci_channel_state_t state)
+void pci_cor_error_detected(struct pci_dev *pdev)
{
+ cxl_cor_error_detected(&pdev->dev);
+}
+EXPORT_SYMBOL_NS_GPL(pci_cor_error_detected, "CXL");
+
+pci_ers_result_t cxl_error_detected(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
- struct cxl_memdev *cxlmd = cxlds->cxlmd;
- struct device *dev = &cxlmd->dev;
- bool ue;
+ struct device *cxlmd_dev = &cxlds->cxlmd->dev;
- scoped_guard(device, dev) {
- if (!dev->driver) {
- dev_warn(&pdev->dev,
- "%s: memdev disabled, abort error handling\n",
- dev_name(dev));
- return PCI_ERS_RESULT_DISCONNECT;
- }
+ guard(device)(cxlmd_dev);
- if (cxlds->rcd)
- cxl_handle_rdport_errors(cxlds);
- /*
- * A frozen channel indicates an impending reset which is fatal to
- * CXL.mem operation, and will likely crash the system. On the off
- * chance the situation is recoverable dump the status of the RAS
- * capability registers and bounce the active state of the memdev.
- */
- ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
- }
-
-
- switch (state) {
- case pci_channel_io_normal:
- if (ue) {
- device_release_driver(dev);
- return PCI_ERS_RESULT_NEED_RESET;
- }
- return PCI_ERS_RESULT_CAN_RECOVER;
- case pci_channel_io_frozen:
+ if (!dev->driver) {
dev_warn(&pdev->dev,
- "%s: frozen state error detected, disable CXL.mem\n",
+ "%s: memdev disabled, abort error handling\n",
dev_name(dev));
- device_release_driver(dev);
- return PCI_ERS_RESULT_NEED_RESET;
- case pci_channel_io_perm_failure:
- dev_warn(&pdev->dev,
- "failure state error detected, request disconnect\n");
return PCI_ERS_RESULT_DISCONNECT;
}
- return PCI_ERS_RESULT_NEED_RESET;
+
+ if (cxlds->rcd)
+ cxl_handle_rdport_errors(cxlds);
+
+ /*
+ * A frozen channel indicates an impending reset which is fatal to
+ * CXL.mem operation, and will likely crash the system. On the off
+ * chance the situation is recoverable dump the status of the RAS
+ * capability registers and bounce the active state of the memdev.
+ */
+ return cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
}
EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL");
+
+pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t error)
+{
+ pci_ers_result_t rc;
+
+ rc = cxl_error_detected(&pdev->dev);
+ if (rc == PCI_ERS_RESULT_PANIC)
+ panic("CXL cachemem error.");
+
+ return rc;
+}
+EXPORT_SYMBOL_NS_GPL(pci_error_detected, "CXL");
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 3882a089ae77..189cd8fabc2c 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -77,19 +77,4 @@ static inline bool cxl_pci_flit_256(struct pci_dev *pdev)
int devm_cxl_port_enumerate_dports(struct cxl_port *port);
struct cxl_dev_state;
void read_cdat_data(struct cxl_port *port);
-
-#ifdef CONFIG_CXL_RAS
-void cxl_cor_error_detected(struct pci_dev *pdev);
-pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
- pci_channel_state_t state);
-#else
-static inline void cxl_cor_error_detected(struct pci_dev *pdev) { }
-
-static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
- pci_channel_state_t state)
-{
- return PCI_ERS_RESULT_NONE;
-}
-#endif
-
#endif /* __CXL_PCI_H__ */
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index bd95be1f3d5c..71fb8709081e 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -16,6 +16,7 @@
#include "cxlpci.h"
#include "cxl.h"
#include "pmu.h"
+#include "core/core.h"
/**
* DOC: cxl pci
@@ -1112,11 +1113,11 @@ static void cxl_reset_done(struct pci_dev *pdev)
}
}
-static const struct pci_error_handlers cxl_error_handlers = {
- .error_detected = cxl_error_detected,
+static const struct pci_error_handlers pci_error_handlers = {
+ .error_detected = pci_error_detected,
.slot_reset = cxl_slot_reset,
.resume = cxl_error_resume,
- .cor_error_detected = cxl_cor_error_detected,
+ .cor_error_detected = pci_cor_error_detected,
.reset_done = cxl_reset_done,
};
@@ -1124,7 +1125,7 @@ static struct pci_driver cxl_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = cxl_mem_pci_tbl,
.probe = cxl_pci_probe,
- .err_handler = &cxl_error_handlers,
+ .err_handler = &pci_error_handlers,
.dev_groups = cxl_rcd_groups,
.driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 17/25] cxl/pci: Introduce CXL Endpoint protocol error handlers
2025-09-25 22:34 ` [PATCH v12 17/25] cxl/pci: Introduce CXL Endpoint protocol error handlers Terry Bowman
@ 2025-09-26 22:04 ` Dave Jiang
2025-09-30 14:06 ` Bowman, Terry
2025-10-03 20:12 ` Cheatham, Benjamin
1 sibling, 1 reply; 92+ messages in thread
From: Dave Jiang @ 2025-09-26 22:04 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> CXL Endpoint protocol errors are currently handled using PCI error
> handlers. The CXL Endpoint requires CXL specific handling in the case of
> uncorrectable error (UCE) handling not provided by the PCI handlers.
>
> Add CXL specific handlers for CXL Endpoints. Rename the existing
> cxl_error_handlers to be pci_error_handlers to more correctly indicate
> the error type and follow naming consistency.
>
> The PCI handlers will be called if the CXL device is not trained for
> alternate protocol (CXL). Update the CXL Endpoint PCI handlers to call the
> CXL UCE handlers.
>
> The existing EP UCE handler includes checks for various results. These are
> no longer needed because CXL UCE recovery will not be attempted. Implement
> cxl_handle_ras() to return PCI_ERS_RESULT_NONE or PCI_ERS_RESULT_PANIC. The
> CXL UCE handler is called by cxl_do_recovery() that acts on the return
> value. In the case of the PCI handler path, call panic() if the result is
> PCI_ERS_RESULT_PANIC.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> ---
>
> Changes in v11->v12:
> - None
>
> Changes in v10->v11:
> - cxl_error_detected() - Change handlers' scoped_guard() to guard() (Jonathan)
> - cxl_error_detected() - Remove extra line (Shiju)
> - Changes moved to core/ras.c (Terry)
> - cxl_error_detected(), remove 'ue' and return with function call. (Jonathan)
> - Remove extra space in documentation for PCI_ERS_RESULT_PANIC definition
> - Move #include "pci.h from cxl.h to core.h (Terry)
> - Remove unnecessary includes of cxl.h and core.h in mem.c (Terry)
> ---
> drivers/cxl/core/core.h | 17 +++++++
> drivers/cxl/core/ras.c | 110 +++++++++++++++++++---------------------
> drivers/cxl/cxlpci.h | 15 ------
> drivers/cxl/pci.c | 9 ++--
> 4 files changed, 75 insertions(+), 76 deletions(-)
>
> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
> index 8c51a2631716..74c64d458f12 100644
> --- a/drivers/cxl/core/core.h
> +++ b/drivers/cxl/core/core.h
> @@ -6,6 +6,7 @@
>
> #include <cxl/mailbox.h>
> #include <linux/rwsem.h>
> +#include <linux/pci.h>
>
> extern const struct device_type cxl_nvdimm_bridge_type;
> extern const struct device_type cxl_nvdimm_type;
> @@ -150,6 +151,11 @@ void cxl_ras_exit(void);
> void cxl_switch_port_init_ras(struct cxl_port *port);
> void cxl_endpoint_port_init_ras(struct cxl_port *ep);
> void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
> +pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
> + pci_channel_state_t error);
> +void pci_cor_error_detected(struct pci_dev *pdev);
> +void cxl_cor_error_detected(struct device *dev);
> +pci_ers_result_t cxl_error_detected(struct device *dev);
> #else
> static inline int cxl_ras_init(void)
> {
> @@ -163,6 +169,17 @@ static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
> static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
> static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
> struct device *host) { }
> +static inline pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
> + pci_channel_state_t error)
> +{
> + return PCI_ERS_RESULT_NONE;
> +}
> +static inline void pci_cor_error_detected(struct pci_dev *pdev) { }
> +static inline void cxl_cor_error_detected(struct device *dev) { }
> +static inline pci_ers_result_t cxl_error_detected(struct device *dev)
> +{
> + return PCI_ERS_RESULT_NONE;
> +}
> #endif // CONFIG_CXL_RAS
>
> int cxl_gpf_port_setup(struct cxl_dport *dport);
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 14a434bd68f0..39472d82d586 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -129,7 +129,7 @@ void cxl_ras_exit(void)
> }
>
> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base);
> -static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>
> #ifdef CONFIG_CXL_RCH_RAS
> static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
> @@ -371,7 +371,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
> * Log the state of the RAS status registers and prepare them to log the
> * next error status. Return 1 if reset needed.
> */
> -static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
> {
> u32 hl[CXL_HEADERLOG_SIZE_U32];
> void __iomem *addr;
> @@ -380,13 +380,13 @@ static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_bas
>
> if (!ras_base) {
> dev_warn_once(dev, "CXL RAS register block is not mapped");
> - return false;
> + return PCI_ERS_RESULT_NONE;
> }
>
> addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
> status = readl(addr);
> if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
> - return false;
> + return PCI_ERS_RESULT_NONE;
>
> /* If multiple errors, log header points to first error from ctrl reg */
> if (hweight32(status) > 1) {
> @@ -403,76 +403,72 @@ static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_bas
> trace_cxl_aer_uncorrectable_error(dev, status, fe, hl, serial);
> writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
>
> - return true;
> + return PCI_ERS_RESULT_PANIC;
> }
>
> -void cxl_cor_error_detected(struct pci_dev *pdev)
> +void cxl_cor_error_detected(struct device *dev)
Why change the input parameter to 'struct device' to just convert it back in the first parameter? I understand that later on cxl_handle_proto_error() will pass in a 'dev', but since it's going to be a pci_dev anyways, can you just pass in a pci_dev instead of doing all this back and forth?
> {
> + struct pci_dev *pdev = to_pci_dev(dev);
> struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> - struct device *dev = &cxlds->cxlmd->dev;
> + struct device *cxlmd_dev = &cxlds->cxlmd->dev;
>
> - scoped_guard(device, dev) {
> - if (!dev->driver) {
> - dev_warn(&pdev->dev,
> - "%s: memdev disabled, abort error handling\n",
> - dev_name(dev));
> - return;
> - }
> + guard(device)(cxlmd_dev);
>
> - if (cxlds->rcd)
> - cxl_handle_rdport_errors(cxlds);
> -
> - cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
> + if (!cxlmd_dev->driver) {
> + dev_warn(&pdev->dev, "%s: memdev disabled, abort error handling", dev_name(dev));
> + return;
> }
> +
> + if (cxlds->rcd)
> + cxl_handle_rdport_errors(cxlds);
> +
> + cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
> }
> EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
>
> -pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
> - pci_channel_state_t state)
> +void pci_cor_error_detected(struct pci_dev *pdev)
> {
> + cxl_cor_error_detected(&pdev->dev);
> +}
> +EXPORT_SYMBOL_NS_GPL(pci_cor_error_detected, "CXL");
> +
> +pci_ers_result_t cxl_error_detected(struct device *dev)
Same comment as above.
DJ
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> - struct cxl_memdev *cxlmd = cxlds->cxlmd;
> - struct device *dev = &cxlmd->dev;
> - bool ue;
> + struct device *cxlmd_dev = &cxlds->cxlmd->dev;
>
> - scoped_guard(device, dev) {
> - if (!dev->driver) {
> - dev_warn(&pdev->dev,
> - "%s: memdev disabled, abort error handling\n",
> - dev_name(dev));
> - return PCI_ERS_RESULT_DISCONNECT;
> - }
> + guard(device)(cxlmd_dev);
>
> - if (cxlds->rcd)
> - cxl_handle_rdport_errors(cxlds);
> - /*
> - * A frozen channel indicates an impending reset which is fatal to
> - * CXL.mem operation, and will likely crash the system. On the off
> - * chance the situation is recoverable dump the status of the RAS
> - * capability registers and bounce the active state of the memdev.
> - */
> - ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
> - }
> -
> -
> - switch (state) {
> - case pci_channel_io_normal:
> - if (ue) {
> - device_release_driver(dev);
> - return PCI_ERS_RESULT_NEED_RESET;
> - }
> - return PCI_ERS_RESULT_CAN_RECOVER;
> - case pci_channel_io_frozen:
> + if (!dev->driver) {
> dev_warn(&pdev->dev,
> - "%s: frozen state error detected, disable CXL.mem\n",
> + "%s: memdev disabled, abort error handling\n",
> dev_name(dev));
> - device_release_driver(dev);
> - return PCI_ERS_RESULT_NEED_RESET;
> - case pci_channel_io_perm_failure:
> - dev_warn(&pdev->dev,
> - "failure state error detected, request disconnect\n");
> return PCI_ERS_RESULT_DISCONNECT;
> }
> - return PCI_ERS_RESULT_NEED_RESET;
> +
> + if (cxlds->rcd)
> + cxl_handle_rdport_errors(cxlds);
> +
> + /*
> + * A frozen channel indicates an impending reset which is fatal to
> + * CXL.mem operation, and will likely crash the system. On the off
> + * chance the situation is recoverable dump the status of the RAS
> + * capability registers and bounce the active state of the memdev.
> + */
> + return cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
> }
> EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL");
> +
> +pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
> + pci_channel_state_t error)
> +{
> + pci_ers_result_t rc;
> +
> + rc = cxl_error_detected(&pdev->dev);
> + if (rc == PCI_ERS_RESULT_PANIC)
> + panic("CXL cachemem error.");
> +
> + return rc;
> +}
> +EXPORT_SYMBOL_NS_GPL(pci_error_detected, "CXL");
> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
> index 3882a089ae77..189cd8fabc2c 100644
> --- a/drivers/cxl/cxlpci.h
> +++ b/drivers/cxl/cxlpci.h
> @@ -77,19 +77,4 @@ static inline bool cxl_pci_flit_256(struct pci_dev *pdev)
> int devm_cxl_port_enumerate_dports(struct cxl_port *port);
> struct cxl_dev_state;
> void read_cdat_data(struct cxl_port *port);
> -
> -#ifdef CONFIG_CXL_RAS
> -void cxl_cor_error_detected(struct pci_dev *pdev);
> -pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
> - pci_channel_state_t state);
> -#else
> -static inline void cxl_cor_error_detected(struct pci_dev *pdev) { }
> -
> -static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
> - pci_channel_state_t state)
> -{
> - return PCI_ERS_RESULT_NONE;
> -}
> -#endif
> -
> #endif /* __CXL_PCI_H__ */
> diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> index bd95be1f3d5c..71fb8709081e 100644
> --- a/drivers/cxl/pci.c
> +++ b/drivers/cxl/pci.c
> @@ -16,6 +16,7 @@
> #include "cxlpci.h"
> #include "cxl.h"
> #include "pmu.h"
> +#include "core/core.h"
>
> /**
> * DOC: cxl pci
> @@ -1112,11 +1113,11 @@ static void cxl_reset_done(struct pci_dev *pdev)
> }
> }
>
> -static const struct pci_error_handlers cxl_error_handlers = {
> - .error_detected = cxl_error_detected,
> +static const struct pci_error_handlers pci_error_handlers = {
> + .error_detected = pci_error_detected,
> .slot_reset = cxl_slot_reset,
> .resume = cxl_error_resume,
> - .cor_error_detected = cxl_cor_error_detected,
> + .cor_error_detected = pci_cor_error_detected,
> .reset_done = cxl_reset_done,
> };
>
> @@ -1124,7 +1125,7 @@ static struct pci_driver cxl_pci_driver = {
> .name = KBUILD_MODNAME,
> .id_table = cxl_mem_pci_tbl,
> .probe = cxl_pci_probe,
> - .err_handler = &cxl_error_handlers,
> + .err_handler = &pci_error_handlers,
> .dev_groups = cxl_rcd_groups,
> .driver = {
> .probe_type = PROBE_PREFER_ASYNCHRONOUS,
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 17/25] cxl/pci: Introduce CXL Endpoint protocol error handlers
2025-09-26 22:04 ` Dave Jiang
@ 2025-09-30 14:06 ` Bowman, Terry
2025-09-30 16:09 ` Dave Jiang
0 siblings, 1 reply; 92+ messages in thread
From: Bowman, Terry @ 2025-09-30 14:06 UTC (permalink / raw)
To: Dave Jiang, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/26/2025 5:04 PM, Dave Jiang wrote:
> On 9/25/25 3:34 PM, Terry Bowman wrote:
>> CXL Endpoint protocol errors are currently handled using PCI error
>> handlers. The CXL Endpoint requires CXL specific handling in the case of
>> uncorrectable error (UCE) handling not provided by the PCI handlers.
>>
>> Add CXL specific handlers for CXL Endpoints. Rename the existing
>> cxl_error_handlers to be pci_error_handlers to more correctly indicate
>> the error type and follow naming consistency.
>>
>> The PCI handlers will be called if the CXL device is not trained for
>> alternate protocol (CXL). Update the CXL Endpoint PCI handlers to call the
>> CXL UCE handlers.
>>
>> The existing EP UCE handler includes checks for various results. These are
>> no longer needed because CXL UCE recovery will not be attempted. Implement
>> cxl_handle_ras() to return PCI_ERS_RESULT_NONE or PCI_ERS_RESULT_PANIC. The
>> CXL UCE handler is called by cxl_do_recovery() that acts on the return
>> value. In the case of the PCI handler path, call panic() if the result is
>> PCI_ERS_RESULT_PANIC.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>>
>> ---
>>
>> Changes in v11->v12:
>> - None
>>
>> Changes in v10->v11:
>> - cxl_error_detected() - Change handlers' scoped_guard() to guard() (Jonathan)
>> - cxl_error_detected() - Remove extra line (Shiju)
>> - Changes moved to core/ras.c (Terry)
>> - cxl_error_detected(), remove 'ue' and return with function call. (Jonathan)
>> - Remove extra space in documentation for PCI_ERS_RESULT_PANIC definition
>> - Move #include "pci.h from cxl.h to core.h (Terry)
>> - Remove unnecessary includes of cxl.h and core.h in mem.c (Terry)
>> ---
>> drivers/cxl/core/core.h | 17 +++++++
>> drivers/cxl/core/ras.c | 110 +++++++++++++++++++---------------------
>> drivers/cxl/cxlpci.h | 15 ------
>> drivers/cxl/pci.c | 9 ++--
>> 4 files changed, 75 insertions(+), 76 deletions(-)
>>
>> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
>> index 8c51a2631716..74c64d458f12 100644
>> --- a/drivers/cxl/core/core.h
>> +++ b/drivers/cxl/core/core.h
>> @@ -6,6 +6,7 @@
>>
>> #include <cxl/mailbox.h>
>> #include <linux/rwsem.h>
>> +#include <linux/pci.h>
>>
>> extern const struct device_type cxl_nvdimm_bridge_type;
>> extern const struct device_type cxl_nvdimm_type;
>> @@ -150,6 +151,11 @@ void cxl_ras_exit(void);
>> void cxl_switch_port_init_ras(struct cxl_port *port);
>> void cxl_endpoint_port_init_ras(struct cxl_port *ep);
>> void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>> +pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
>> + pci_channel_state_t error);
>> +void pci_cor_error_detected(struct pci_dev *pdev);
>> +void cxl_cor_error_detected(struct device *dev);
>> +pci_ers_result_t cxl_error_detected(struct device *dev);
>> #else
>> static inline int cxl_ras_init(void)
>> {
>> @@ -163,6 +169,17 @@ static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
>> static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
>> static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>> struct device *host) { }
>> +static inline pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
>> + pci_channel_state_t error)
>> +{
>> + return PCI_ERS_RESULT_NONE;
>> +}
>> +static inline void pci_cor_error_detected(struct pci_dev *pdev) { }
>> +static inline void cxl_cor_error_detected(struct device *dev) { }
>> +static inline pci_ers_result_t cxl_error_detected(struct device *dev)
>> +{
>> + return PCI_ERS_RESULT_NONE;
>> +}
>> #endif // CONFIG_CXL_RAS
>>
>> int cxl_gpf_port_setup(struct cxl_dport *dport);
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 14a434bd68f0..39472d82d586 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -129,7 +129,7 @@ void cxl_ras_exit(void)
>> }
>>
>> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>> -static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>>
>> #ifdef CONFIG_CXL_RCH_RAS
>> static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
>> @@ -371,7 +371,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
>> * Log the state of the RAS status registers and prepare them to log the
>> * next error status. Return 1 if reset needed.
>> */
>> -static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>> {
>> u32 hl[CXL_HEADERLOG_SIZE_U32];
>> void __iomem *addr;
>> @@ -380,13 +380,13 @@ static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_bas
>>
>> if (!ras_base) {
>> dev_warn_once(dev, "CXL RAS register block is not mapped");
>> - return false;
>> + return PCI_ERS_RESULT_NONE;
>> }
>>
>> addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
>> status = readl(addr);
>> if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
>> - return false;
>> + return PCI_ERS_RESULT_NONE;
>>
>> /* If multiple errors, log header points to first error from ctrl reg */
>> if (hweight32(status) > 1) {
>> @@ -403,76 +403,72 @@ static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_bas
>> trace_cxl_aer_uncorrectable_error(dev, status, fe, hl, serial);
>> writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
>>
>> - return true;
>> + return PCI_ERS_RESULT_PANIC;
>> }
>>
>> -void cxl_cor_error_detected(struct pci_dev *pdev)
>> +void cxl_cor_error_detected(struct device *dev)
> Why change the input parameter to 'struct device' to just convert it back in the first parameter? I understand that later on cxl_handle_proto_error() will pass in a 'dev', but since it's going to be a pci_dev anyways, can you just pass in a pci_dev instead of doing all this back and forth?
Dan made a point in previous revision that handling functions should work on
devices (to include the parameter). This is to be consistent with CXL device/port error
handling rather than PCIe error handling. Let me know how to proceed.
Terry
>> {
>> + struct pci_dev *pdev = to_pci_dev(dev);
>> struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>> - struct device *dev = &cxlds->cxlmd->dev;
>> + struct device *cxlmd_dev = &cxlds->cxlmd->dev;
>>
>> - scoped_guard(device, dev) {
>> - if (!dev->driver) {
>> - dev_warn(&pdev->dev,
>> - "%s: memdev disabled, abort error handling\n",
>> - dev_name(dev));
>> - return;
>> - }
>> + guard(device)(cxlmd_dev);
>>
>> - if (cxlds->rcd)
>> - cxl_handle_rdport_errors(cxlds);
>> -
>> - cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>> + if (!cxlmd_dev->driver) {
>> + dev_warn(&pdev->dev, "%s: memdev disabled, abort error handling", dev_name(dev));
>> + return;
>> }
>> +
>> + if (cxlds->rcd)
>> + cxl_handle_rdport_errors(cxlds);
>> +
>> + cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>> }
>> EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
>>
>> -pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>> - pci_channel_state_t state)
>> +void pci_cor_error_detected(struct pci_dev *pdev)
>> {
>> + cxl_cor_error_detected(&pdev->dev);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(pci_cor_error_detected, "CXL");
>> +
>> +pci_ers_result_t cxl_error_detected(struct device *dev)
> Same comment as above.
>
> DJ
>
>> +{
>> + struct pci_dev *pdev = to_pci_dev(dev);
>> struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>> - struct cxl_memdev *cxlmd = cxlds->cxlmd;
>> - struct device *dev = &cxlmd->dev;
>> - bool ue;
>> + struct device *cxlmd_dev = &cxlds->cxlmd->dev;
>>
>> - scoped_guard(device, dev) {
>> - if (!dev->driver) {
>> - dev_warn(&pdev->dev,
>> - "%s: memdev disabled, abort error handling\n",
>> - dev_name(dev));
>> - return PCI_ERS_RESULT_DISCONNECT;
>> - }
>> + guard(device)(cxlmd_dev);
>>
>> - if (cxlds->rcd)
>> - cxl_handle_rdport_errors(cxlds);
>> - /*
>> - * A frozen channel indicates an impending reset which is fatal to
>> - * CXL.mem operation, and will likely crash the system. On the off
>> - * chance the situation is recoverable dump the status of the RAS
>> - * capability registers and bounce the active state of the memdev.
>> - */
>> - ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>> - }
>> -
>> -
>> - switch (state) {
>> - case pci_channel_io_normal:
>> - if (ue) {
>> - device_release_driver(dev);
>> - return PCI_ERS_RESULT_NEED_RESET;
>> - }
>> - return PCI_ERS_RESULT_CAN_RECOVER;
>> - case pci_channel_io_frozen:
>> + if (!dev->driver) {
>> dev_warn(&pdev->dev,
>> - "%s: frozen state error detected, disable CXL.mem\n",
>> + "%s: memdev disabled, abort error handling\n",
>> dev_name(dev));
>> - device_release_driver(dev);
>> - return PCI_ERS_RESULT_NEED_RESET;
>> - case pci_channel_io_perm_failure:
>> - dev_warn(&pdev->dev,
>> - "failure state error detected, request disconnect\n");
>> return PCI_ERS_RESULT_DISCONNECT;
>> }
>> - return PCI_ERS_RESULT_NEED_RESET;
>> +
>> + if (cxlds->rcd)
>> + cxl_handle_rdport_errors(cxlds);
>> +
>> + /*
>> + * A frozen channel indicates an impending reset which is fatal to
>> + * CXL.mem operation, and will likely crash the system. On the off
>> + * chance the situation is recoverable dump the status of the RAS
>> + * capability registers and bounce the active state of the memdev.
>> + */
>> + return cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>> }
>> EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL");
>> +
>> +pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
>> + pci_channel_state_t error)
>> +{
>> + pci_ers_result_t rc;
>> +
>> + rc = cxl_error_detected(&pdev->dev);
>> + if (rc == PCI_ERS_RESULT_PANIC)
>> + panic("CXL cachemem error.");
>> +
>> + return rc;
>> +}
>> +EXPORT_SYMBOL_NS_GPL(pci_error_detected, "CXL");
>> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
>> index 3882a089ae77..189cd8fabc2c 100644
>> --- a/drivers/cxl/cxlpci.h
>> +++ b/drivers/cxl/cxlpci.h
>> @@ -77,19 +77,4 @@ static inline bool cxl_pci_flit_256(struct pci_dev *pdev)
>> int devm_cxl_port_enumerate_dports(struct cxl_port *port);
>> struct cxl_dev_state;
>> void read_cdat_data(struct cxl_port *port);
>> -
>> -#ifdef CONFIG_CXL_RAS
>> -void cxl_cor_error_detected(struct pci_dev *pdev);
>> -pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>> - pci_channel_state_t state);
>> -#else
>> -static inline void cxl_cor_error_detected(struct pci_dev *pdev) { }
>> -
>> -static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>> - pci_channel_state_t state)
>> -{
>> - return PCI_ERS_RESULT_NONE;
>> -}
>> -#endif
>> -
>> #endif /* __CXL_PCI_H__ */
>> diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
>> index bd95be1f3d5c..71fb8709081e 100644
>> --- a/drivers/cxl/pci.c
>> +++ b/drivers/cxl/pci.c
>> @@ -16,6 +16,7 @@
>> #include "cxlpci.h"
>> #include "cxl.h"
>> #include "pmu.h"
>> +#include "core/core.h"
>>
>> /**
>> * DOC: cxl pci
>> @@ -1112,11 +1113,11 @@ static void cxl_reset_done(struct pci_dev *pdev)
>> }
>> }
>>
>> -static const struct pci_error_handlers cxl_error_handlers = {
>> - .error_detected = cxl_error_detected,
>> +static const struct pci_error_handlers pci_error_handlers = {
>> + .error_detected = pci_error_detected,
>> .slot_reset = cxl_slot_reset,
>> .resume = cxl_error_resume,
>> - .cor_error_detected = cxl_cor_error_detected,
>> + .cor_error_detected = pci_cor_error_detected,
>> .reset_done = cxl_reset_done,
>> };
>>
>> @@ -1124,7 +1125,7 @@ static struct pci_driver cxl_pci_driver = {
>> .name = KBUILD_MODNAME,
>> .id_table = cxl_mem_pci_tbl,
>> .probe = cxl_pci_probe,
>> - .err_handler = &cxl_error_handlers,
>> + .err_handler = &pci_error_handlers,
>> .dev_groups = cxl_rcd_groups,
>> .driver = {
>> .probe_type = PROBE_PREFER_ASYNCHRONOUS,
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 17/25] cxl/pci: Introduce CXL Endpoint protocol error handlers
2025-09-30 14:06 ` Bowman, Terry
@ 2025-09-30 16:09 ` Dave Jiang
0 siblings, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-30 16:09 UTC (permalink / raw)
To: Bowman, Terry, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/30/25 7:06 AM, Bowman, Terry wrote:
>
>
> On 9/26/2025 5:04 PM, Dave Jiang wrote:
>> On 9/25/25 3:34 PM, Terry Bowman wrote:
>>> CXL Endpoint protocol errors are currently handled using PCI error
>>> handlers. The CXL Endpoint requires CXL specific handling in the case of
>>> uncorrectable error (UCE) handling not provided by the PCI handlers.
>>>
>>> Add CXL specific handlers for CXL Endpoints. Rename the existing
>>> cxl_error_handlers to be pci_error_handlers to more correctly indicate
>>> the error type and follow naming consistency.
>>>
>>> The PCI handlers will be called if the CXL device is not trained for
>>> alternate protocol (CXL). Update the CXL Endpoint PCI handlers to call the
>>> CXL UCE handlers.
>>>
>>> The existing EP UCE handler includes checks for various results. These are
>>> no longer needed because CXL UCE recovery will not be attempted. Implement
>>> cxl_handle_ras() to return PCI_ERS_RESULT_NONE or PCI_ERS_RESULT_PANIC. The
>>> CXL UCE handler is called by cxl_do_recovery() that acts on the return
>>> value. In the case of the PCI handler path, call panic() if the result is
>>> PCI_ERS_RESULT_PANIC.
>>>
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>>>
>>> ---
>>>
>>> Changes in v11->v12:
>>> - None
>>>
>>> Changes in v10->v11:
>>> - cxl_error_detected() - Change handlers' scoped_guard() to guard() (Jonathan)
>>> - cxl_error_detected() - Remove extra line (Shiju)
>>> - Changes moved to core/ras.c (Terry)
>>> - cxl_error_detected(), remove 'ue' and return with function call. (Jonathan)
>>> - Remove extra space in documentation for PCI_ERS_RESULT_PANIC definition
>>> - Move #include "pci.h from cxl.h to core.h (Terry)
>>> - Remove unnecessary includes of cxl.h and core.h in mem.c (Terry)
>>> ---
>>> drivers/cxl/core/core.h | 17 +++++++
>>> drivers/cxl/core/ras.c | 110 +++++++++++++++++++---------------------
>>> drivers/cxl/cxlpci.h | 15 ------
>>> drivers/cxl/pci.c | 9 ++--
>>> 4 files changed, 75 insertions(+), 76 deletions(-)
>>>
>>> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
>>> index 8c51a2631716..74c64d458f12 100644
>>> --- a/drivers/cxl/core/core.h
>>> +++ b/drivers/cxl/core/core.h
>>> @@ -6,6 +6,7 @@
>>>
>>> #include <cxl/mailbox.h>
>>> #include <linux/rwsem.h>
>>> +#include <linux/pci.h>
>>>
>>> extern const struct device_type cxl_nvdimm_bridge_type;
>>> extern const struct device_type cxl_nvdimm_type;
>>> @@ -150,6 +151,11 @@ void cxl_ras_exit(void);
>>> void cxl_switch_port_init_ras(struct cxl_port *port);
>>> void cxl_endpoint_port_init_ras(struct cxl_port *ep);
>>> void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>>> +pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
>>> + pci_channel_state_t error);
>>> +void pci_cor_error_detected(struct pci_dev *pdev);
>>> +void cxl_cor_error_detected(struct device *dev);
>>> +pci_ers_result_t cxl_error_detected(struct device *dev);
>>> #else
>>> static inline int cxl_ras_init(void)
>>> {
>>> @@ -163,6 +169,17 @@ static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
>>> static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
>>> static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>>> struct device *host) { }
>>> +static inline pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
>>> + pci_channel_state_t error)
>>> +{
>>> + return PCI_ERS_RESULT_NONE;
>>> +}
>>> +static inline void pci_cor_error_detected(struct pci_dev *pdev) { }
>>> +static inline void cxl_cor_error_detected(struct device *dev) { }
>>> +static inline pci_ers_result_t cxl_error_detected(struct device *dev)
>>> +{
>>> + return PCI_ERS_RESULT_NONE;
>>> +}
>>> #endif // CONFIG_CXL_RAS
>>>
>>> int cxl_gpf_port_setup(struct cxl_dport *dport);
>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>> index 14a434bd68f0..39472d82d586 100644
>>> --- a/drivers/cxl/core/ras.c
>>> +++ b/drivers/cxl/core/ras.c
>>> @@ -129,7 +129,7 @@ void cxl_ras_exit(void)
>>> }
>>>
>>> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>>> -static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>>> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>>>
>>> #ifdef CONFIG_CXL_RCH_RAS
>>> static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
>>> @@ -371,7 +371,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
>>> * Log the state of the RAS status registers and prepare them to log the
>>> * next error status. Return 1 if reset needed.
>>> */
>>> -static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>>> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>>> {
>>> u32 hl[CXL_HEADERLOG_SIZE_U32];
>>> void __iomem *addr;
>>> @@ -380,13 +380,13 @@ static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_bas
>>>
>>> if (!ras_base) {
>>> dev_warn_once(dev, "CXL RAS register block is not mapped");
>>> - return false;
>>> + return PCI_ERS_RESULT_NONE;
>>> }
>>>
>>> addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
>>> status = readl(addr);
>>> if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
>>> - return false;
>>> + return PCI_ERS_RESULT_NONE;
>>>
>>> /* If multiple errors, log header points to first error from ctrl reg */
>>> if (hweight32(status) > 1) {
>>> @@ -403,76 +403,72 @@ static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_bas
>>> trace_cxl_aer_uncorrectable_error(dev, status, fe, hl, serial);
>>> writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
>>>
>>> - return true;
>>> + return PCI_ERS_RESULT_PANIC;
>>> }
>>>
>>> -void cxl_cor_error_detected(struct pci_dev *pdev)
>>> +void cxl_cor_error_detected(struct device *dev)
>> Why change the input parameter to 'struct device' to just convert it back in the first parameter? I understand that later on cxl_handle_proto_error() will pass in a 'dev', but since it's going to be a pci_dev anyways, can you just pass in a pci_dev instead of doing all this back and forth?
>
> Dan made a point in previous revision that handling functions should work on
> devices (to include the parameter). This is to be consistent with CXL device/port error
> handling rather than PCIe error handling. Let me know how to proceed.
Well, these are all PCI AER based handlers so they operate only on PCI devices.... If we are keeping it as 'struct device', I think we should add a check to make sure it's a pci device before doing any conversion from device to pci_dev.
DJ
>
> Terry
>>> {
>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>> struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>>> - struct device *dev = &cxlds->cxlmd->dev;
>>> + struct device *cxlmd_dev = &cxlds->cxlmd->dev;
>>>
>>> - scoped_guard(device, dev) {
>>> - if (!dev->driver) {
>>> - dev_warn(&pdev->dev,
>>> - "%s: memdev disabled, abort error handling\n",
>>> - dev_name(dev));
>>> - return;
>>> - }
>>> + guard(device)(cxlmd_dev);
>>>
>>> - if (cxlds->rcd)
>>> - cxl_handle_rdport_errors(cxlds);
>>> -
>>> - cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>>> + if (!cxlmd_dev->driver) {
>>> + dev_warn(&pdev->dev, "%s: memdev disabled, abort error handling", dev_name(dev));
>>> + return;
>>> }
>>> +
>>> + if (cxlds->rcd)
>>> + cxl_handle_rdport_errors(cxlds);
>>> +
>>> + cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>>> }
>>> EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
>>>
>>> -pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>>> - pci_channel_state_t state)
>>> +void pci_cor_error_detected(struct pci_dev *pdev)
>>> {
>>> + cxl_cor_error_detected(&pdev->dev);
>>> +}
>>> +EXPORT_SYMBOL_NS_GPL(pci_cor_error_detected, "CXL");
>>> +
>>> +pci_ers_result_t cxl_error_detected(struct device *dev)
>> Same comment as above.
>>
>> DJ
>>
>>> +{
>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>> struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>>> - struct cxl_memdev *cxlmd = cxlds->cxlmd;
>>> - struct device *dev = &cxlmd->dev;
>>> - bool ue;
>>> + struct device *cxlmd_dev = &cxlds->cxlmd->dev;
>>>
>>> - scoped_guard(device, dev) {
>>> - if (!dev->driver) {
>>> - dev_warn(&pdev->dev,
>>> - "%s: memdev disabled, abort error handling\n",
>>> - dev_name(dev));
>>> - return PCI_ERS_RESULT_DISCONNECT;
>>> - }
>>> + guard(device)(cxlmd_dev);
>>>
>>> - if (cxlds->rcd)
>>> - cxl_handle_rdport_errors(cxlds);
>>> - /*
>>> - * A frozen channel indicates an impending reset which is fatal to
>>> - * CXL.mem operation, and will likely crash the system. On the off
>>> - * chance the situation is recoverable dump the status of the RAS
>>> - * capability registers and bounce the active state of the memdev.
>>> - */
>>> - ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>>> - }
>>> -
>>> -
>>> - switch (state) {
>>> - case pci_channel_io_normal:
>>> - if (ue) {
>>> - device_release_driver(dev);
>>> - return PCI_ERS_RESULT_NEED_RESET;
>>> - }
>>> - return PCI_ERS_RESULT_CAN_RECOVER;
>>> - case pci_channel_io_frozen:
>>> + if (!dev->driver) {
>>> dev_warn(&pdev->dev,
>>> - "%s: frozen state error detected, disable CXL.mem\n",
>>> + "%s: memdev disabled, abort error handling\n",
>>> dev_name(dev));
>>> - device_release_driver(dev);
>>> - return PCI_ERS_RESULT_NEED_RESET;
>>> - case pci_channel_io_perm_failure:
>>> - dev_warn(&pdev->dev,
>>> - "failure state error detected, request disconnect\n");
>>> return PCI_ERS_RESULT_DISCONNECT;
>>> }
>>> - return PCI_ERS_RESULT_NEED_RESET;
>>> +
>>> + if (cxlds->rcd)
>>> + cxl_handle_rdport_errors(cxlds);
>>> +
>>> + /*
>>> + * A frozen channel indicates an impending reset which is fatal to
>>> + * CXL.mem operation, and will likely crash the system. On the off
>>> + * chance the situation is recoverable dump the status of the RAS
>>> + * capability registers and bounce the active state of the memdev.
>>> + */
>>> + return cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>>> }
>>> EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL");
>>> +
>>> +pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
>>> + pci_channel_state_t error)
>>> +{
>>> + pci_ers_result_t rc;
>>> +
>>> + rc = cxl_error_detected(&pdev->dev);
>>> + if (rc == PCI_ERS_RESULT_PANIC)
>>> + panic("CXL cachemem error.");
>>> +
>>> + return rc;
>>> +}
>>> +EXPORT_SYMBOL_NS_GPL(pci_error_detected, "CXL");
>>> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
>>> index 3882a089ae77..189cd8fabc2c 100644
>>> --- a/drivers/cxl/cxlpci.h
>>> +++ b/drivers/cxl/cxlpci.h
>>> @@ -77,19 +77,4 @@ static inline bool cxl_pci_flit_256(struct pci_dev *pdev)
>>> int devm_cxl_port_enumerate_dports(struct cxl_port *port);
>>> struct cxl_dev_state;
>>> void read_cdat_data(struct cxl_port *port);
>>> -
>>> -#ifdef CONFIG_CXL_RAS
>>> -void cxl_cor_error_detected(struct pci_dev *pdev);
>>> -pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>>> - pci_channel_state_t state);
>>> -#else
>>> -static inline void cxl_cor_error_detected(struct pci_dev *pdev) { }
>>> -
>>> -static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>>> - pci_channel_state_t state)
>>> -{
>>> - return PCI_ERS_RESULT_NONE;
>>> -}
>>> -#endif
>>> -
>>> #endif /* __CXL_PCI_H__ */
>>> diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
>>> index bd95be1f3d5c..71fb8709081e 100644
>>> --- a/drivers/cxl/pci.c
>>> +++ b/drivers/cxl/pci.c
>>> @@ -16,6 +16,7 @@
>>> #include "cxlpci.h"
>>> #include "cxl.h"
>>> #include "pmu.h"
>>> +#include "core/core.h"
>>>
>>> /**
>>> * DOC: cxl pci
>>> @@ -1112,11 +1113,11 @@ static void cxl_reset_done(struct pci_dev *pdev)
>>> }
>>> }
>>>
>>> -static const struct pci_error_handlers cxl_error_handlers = {
>>> - .error_detected = cxl_error_detected,
>>> +static const struct pci_error_handlers pci_error_handlers = {
>>> + .error_detected = pci_error_detected,
>>> .slot_reset = cxl_slot_reset,
>>> .resume = cxl_error_resume,
>>> - .cor_error_detected = cxl_cor_error_detected,
>>> + .cor_error_detected = pci_cor_error_detected,
>>> .reset_done = cxl_reset_done,
>>> };
>>>
>>> @@ -1124,7 +1125,7 @@ static struct pci_driver cxl_pci_driver = {
>>> .name = KBUILD_MODNAME,
>>> .id_table = cxl_mem_pci_tbl,
>>> .probe = cxl_pci_probe,
>>> - .err_handler = &cxl_error_handlers,
>>> + .err_handler = &pci_error_handlers,
>>> .dev_groups = cxl_rcd_groups,
>>> .driver = {
>>> .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 17/25] cxl/pci: Introduce CXL Endpoint protocol error handlers
2025-09-25 22:34 ` [PATCH v12 17/25] cxl/pci: Introduce CXL Endpoint protocol error handlers Terry Bowman
2025-09-26 22:04 ` Dave Jiang
@ 2025-10-03 20:12 ` Cheatham, Benjamin
2025-10-06 21:07 ` Bowman, Terry
1 sibling, 1 reply; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:12 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> CXL Endpoint protocol errors are currently handled using PCI error
> handlers. The CXL Endpoint requires CXL specific handling in the case of
> uncorrectable error (UCE) handling not provided by the PCI handlers.
>
> Add CXL specific handlers for CXL Endpoints. Rename the existing
> cxl_error_handlers to be pci_error_handlers to more correctly indicate
> the error type and follow naming consistency.
>
> The PCI handlers will be called if the CXL device is not trained for
> alternate protocol (CXL). Update the CXL Endpoint PCI handlers to call the
> CXL UCE handlers.
>
> The existing EP UCE handler includes checks for various results. These are
> no longer needed because CXL UCE recovery will not be attempted. Implement
> cxl_handle_ras() to return PCI_ERS_RESULT_NONE or PCI_ERS_RESULT_PANIC. The
> CXL UCE handler is called by cxl_do_recovery() that acts on the return
> value. In the case of the PCI handler path, call panic() if the result is
> PCI_ERS_RESULT_PANIC.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> ---
>
> Changes in v11->v12:
> - None
>
> Changes in v10->v11:
> - cxl_error_detected() - Change handlers' scoped_guard() to guard() (Jonathan)
> - cxl_error_detected() - Remove extra line (Shiju)
> - Changes moved to core/ras.c (Terry)
> - cxl_error_detected(), remove 'ue' and return with function call. (Jonathan)
> - Remove extra space in documentation for PCI_ERS_RESULT_PANIC definition
> - Move #include "pci.h from cxl.h to core.h (Terry)
> - Remove unnecessary includes of cxl.h and core.h in mem.c (Terry)
> ---
> drivers/cxl/core/core.h | 17 +++++++
> drivers/cxl/core/ras.c | 110 +++++++++++++++++++---------------------
> drivers/cxl/cxlpci.h | 15 ------
> drivers/cxl/pci.c | 9 ++--
> 4 files changed, 75 insertions(+), 76 deletions(-)
>
> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
> index 8c51a2631716..74c64d458f12 100644
> --- a/drivers/cxl/core/core.h
> +++ b/drivers/cxl/core/core.h
> @@ -6,6 +6,7 @@
>
> #include <cxl/mailbox.h>
> #include <linux/rwsem.h>
> +#include <linux/pci.h>
>
> extern const struct device_type cxl_nvdimm_bridge_type;
> extern const struct device_type cxl_nvdimm_type;
> @@ -150,6 +151,11 @@ void cxl_ras_exit(void);
> void cxl_switch_port_init_ras(struct cxl_port *port);
> void cxl_endpoint_port_init_ras(struct cxl_port *ep);
> void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
> +pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
> + pci_channel_state_t error);
> +void pci_cor_error_detected(struct pci_dev *pdev);
> +void cxl_cor_error_detected(struct device *dev);
> +pci_ers_result_t cxl_error_detected(struct device *dev);
> #else
> static inline int cxl_ras_init(void)
> {
> @@ -163,6 +169,17 @@ static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
> static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
> static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
> struct device *host) { }
> +static inline pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
> + pci_channel_state_t error)
> +{
> + return PCI_ERS_RESULT_NONE;
> +}
> +static inline void pci_cor_error_detected(struct pci_dev *pdev) { }
> +static inline void cxl_cor_error_detected(struct device *dev) { }
> +static inline pci_ers_result_t cxl_error_detected(struct device *dev)
> +{
> + return PCI_ERS_RESULT_NONE;
My understanding is this only occurs for uncorrectable errors, so should this be upgraded to
a PCI_ERS_RESULT_PANIC? If uncorrectable errors == system panic, I would expect that to be the
case even if we don't have the code to handle the error built.
I guess it's really a question of how safe you want to be. Is it ok to let uncorrectable errors
propagate when the support is missing, or do we always panic regardless of handling code?
> +}
> #endif // CONFIG_CXL_RAS
>
> int cxl_gpf_port_setup(struct cxl_dport *dport);
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 14a434bd68f0..39472d82d586 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -129,7 +129,7 @@ void cxl_ras_exit(void)
> }
>
> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base);
> -static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>
> #ifdef CONFIG_CXL_RCH_RAS
> static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
> @@ -371,7 +371,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
> * Log the state of the RAS status registers and prepare them to log the
> * next error status. Return 1 if reset needed.
> */
> -static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
> {
> u32 hl[CXL_HEADERLOG_SIZE_U32];
> void __iomem *addr;
> @@ -380,13 +380,13 @@ static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_bas
>
> if (!ras_base) {
> dev_warn_once(dev, "CXL RAS register block is not mapped");
> - return false;
> + return PCI_ERS_RESULT_NONE;
Same idea as above. I would assume since we can't tell the severity of the error we would
just treat it as the worst case scenario.
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 17/25] cxl/pci: Introduce CXL Endpoint protocol error handlers
2025-10-03 20:12 ` Cheatham, Benjamin
@ 2025-10-06 21:07 ` Bowman, Terry
0 siblings, 0 replies; 92+ messages in thread
From: Bowman, Terry @ 2025-10-06 21:07 UTC (permalink / raw)
To: Cheatham, Benjamin
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 10/3/2025 3:12 PM, Cheatham, Benjamin wrote:
> On 9/25/2025 5:34 PM, Terry Bowman wrote:
>> CXL Endpoint protocol errors are currently handled using PCI error
>> handlers. The CXL Endpoint requires CXL specific handling in the case of
>> uncorrectable error (UCE) handling not provided by the PCI handlers.
>>
>> Add CXL specific handlers for CXL Endpoints. Rename the existing
>> cxl_error_handlers to be pci_error_handlers to more correctly indicate
>> the error type and follow naming consistency.
>>
>> The PCI handlers will be called if the CXL device is not trained for
>> alternate protocol (CXL). Update the CXL Endpoint PCI handlers to call the
>> CXL UCE handlers.
>>
>> The existing EP UCE handler includes checks for various results. These are
>> no longer needed because CXL UCE recovery will not be attempted. Implement
>> cxl_handle_ras() to return PCI_ERS_RESULT_NONE or PCI_ERS_RESULT_PANIC. The
>> CXL UCE handler is called by cxl_do_recovery() that acts on the return
>> value. In the case of the PCI handler path, call panic() if the result is
>> PCI_ERS_RESULT_PANIC.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>>
>> ---
>>
>> Changes in v11->v12:
>> - None
>>
>> Changes in v10->v11:
>> - cxl_error_detected() - Change handlers' scoped_guard() to guard() (Jonathan)
>> - cxl_error_detected() - Remove extra line (Shiju)
>> - Changes moved to core/ras.c (Terry)
>> - cxl_error_detected(), remove 'ue' and return with function call. (Jonathan)
>> - Remove extra space in documentation for PCI_ERS_RESULT_PANIC definition
>> - Move #include "pci.h from cxl.h to core.h (Terry)
>> - Remove unnecessary includes of cxl.h and core.h in mem.c (Terry)
>> ---
>> drivers/cxl/core/core.h | 17 +++++++
>> drivers/cxl/core/ras.c | 110 +++++++++++++++++++---------------------
>> drivers/cxl/cxlpci.h | 15 ------
>> drivers/cxl/pci.c | 9 ++--
>> 4 files changed, 75 insertions(+), 76 deletions(-)
>>
>> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
>> index 8c51a2631716..74c64d458f12 100644
>> --- a/drivers/cxl/core/core.h
>> +++ b/drivers/cxl/core/core.h
>> @@ -6,6 +6,7 @@
>>
>> #include <cxl/mailbox.h>
>> #include <linux/rwsem.h>
>> +#include <linux/pci.h>
>>
>> extern const struct device_type cxl_nvdimm_bridge_type;
>> extern const struct device_type cxl_nvdimm_type;
>> @@ -150,6 +151,11 @@ void cxl_ras_exit(void);
>> void cxl_switch_port_init_ras(struct cxl_port *port);
>> void cxl_endpoint_port_init_ras(struct cxl_port *ep);
>> void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>> +pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
>> + pci_channel_state_t error);
>> +void pci_cor_error_detected(struct pci_dev *pdev);
>> +void cxl_cor_error_detected(struct device *dev);
>> +pci_ers_result_t cxl_error_detected(struct device *dev);
>> #else
>> static inline int cxl_ras_init(void)
>> {
>> @@ -163,6 +169,17 @@ static inline void cxl_switch_port_init_ras(struct cxl_port *port) { }
>> static inline void cxl_endpoint_port_init_ras(struct cxl_port *ep) { }
>> static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>> struct device *host) { }
>> +static inline pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
>> + pci_channel_state_t error)
>> +{
>> + return PCI_ERS_RESULT_NONE;
>> +}
>> +static inline void pci_cor_error_detected(struct pci_dev *pdev) { }
>> +static inline void cxl_cor_error_detected(struct device *dev) { }
>> +static inline pci_ers_result_t cxl_error_detected(struct device *dev)
>> +{
>> + return PCI_ERS_RESULT_NONE;
> My understanding is this only occurs for uncorrectable errors, so should this be upgraded to
> a PCI_ERS_RESULT_PANIC? If uncorrectable errors == system panic, I would expect that to be the
> case even if we don't have the code to handle the error built.
>
> I guess it's really a question of how safe you want to be. Is it ok to let uncorrectable errors
> propagate when the support is missing, or do we always panic regardless of handling code?
Here the CONFIG_CXL_RAS Kconfig is disabled and these function stubs allow the linker to complete
the build.PCI_ERS_RESULT_PANIC isn't returned because it implies handling but handling is
disabled through unset CONFIG_CXL_RAS. If CONFIG_CXL_RAS is disabled then the interrupts
and CXL RAS logic should be disabled.
>> +}
>> #endif // CONFIG_CXL_RAS
>>
>> int cxl_gpf_port_setup(struct cxl_dport *dport);
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 14a434bd68f0..39472d82d586 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -129,7 +129,7 @@ void cxl_ras_exit(void)
>> }
>>
>> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>> -static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>>
>> #ifdef CONFIG_CXL_RCH_RAS
>> static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
>> @@ -371,7 +371,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
>> * Log the state of the RAS status registers and prepare them to log the
>> * next error status. Return 1 if reset needed.
>> */
>> -static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>> {
>> u32 hl[CXL_HEADERLOG_SIZE_U32];
>> void __iomem *addr;
>> @@ -380,13 +380,13 @@ static bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_bas
>>
>> if (!ras_base) {
>> dev_warn_once(dev, "CXL RAS register block is not mapped");
>> - return false;
>> + return PCI_ERS_RESULT_NONE;
> Same idea as above. I would assume since we can't tell the severity of the error we would
> just treat it as the worst case scenario.
>
The RAS UCE status needs to be read and verified as UCE before handling with a panic.
Terry
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 18/25] CXL/AER: Introduce aer_cxl_vh.c in AER driver for forwarding CXL errors
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (16 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 17/25] cxl/pci: Introduce CXL Endpoint protocol error handlers Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-26 22:56 ` Dave Jiang
2025-10-03 20:12 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 19/25] cxl: Introduce cxl_pci_drv_bound() to check for bound driver Terry Bowman
` (6 subsequent siblings)
24 siblings, 2 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
CXL virtual hierarchy (VH) RAS handling for CXL Port devices will be added
soon. This requires a notification mechanism for the AER driver to share
the AER interrupt with the CXL driver. The notification will be used as an
indication for the CXL drivers to handle and log the CXL RAS errors.
Note, 'CXL protocol error' terminology will refer to CXL VH and not
CXL RCH errors unless specifically noted going forward.
Introduce a new file in the AER driver to handle the CXL protocol errors
named pci/pcie/aer_cxl_vh.c.
Add a kfifo work queue to be used by the AER and CXL drivers. The AER
driver will be the sole kfifo producer adding work and the cxl_core will be
the sole kfifo consumer removing work. Add the boilerplate kfifo support.
Encapsulate the kfifo, RW semaphore, and work pointer in a single structure.
Add CXL work queue handler registration functions in the AER driver. Export
the functions allowing CXL driver to access. Implement registration
functions for the CXL driver to assign or clear the work handler function.
Synchronize accesses using the RW semaphore.
Introduce 'struct cxl_proto_err_work_data' to serve as the kfifo work data.
This will contain a reference to the erring PCI device and the error
severity. This will be used when the work is dequeued by the cxl_core driver.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
Changes in v11->v12:
- Rename drivers/pci/pcie/cxl_aer.c to drivers/pci/pcie/aer_cxl_vh.c (Lukas)
Changes in v10->v11:
- cxl_error_detected() - Change handlers' scoped_guard() to guard() (Jonathan)
- cxl_error_detected() - Remove extra line (Shiju)
- Changes moved to core/ras.c (Terry)
- cxl_error_detected(), remove 'ue' and return with function call. (Jonathan)
- Remove extra space in documentation for PCI_ERS_RESULT_PANIC definition
- Move #include "pci.h from cxl.h to core.h (Terry)
- Remove unnecessary includes of cxl.h and core.h in mem.c (Terry)
---
drivers/pci/pci.h | 4 ++
drivers/pci/pcie/Makefile | 1 +
drivers/pci/pcie/aer.c | 25 ++-------
drivers/pci/pcie/aer_cxl_vh.c | 95 +++++++++++++++++++++++++++++++++++
include/linux/aer.h | 17 +++++++
5 files changed, 121 insertions(+), 21 deletions(-)
create mode 100644 drivers/pci/pcie/aer_cxl_vh.c
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f7631f40e57c..22e8f9a18a09 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1234,8 +1234,12 @@ static inline void cxl_rch_enable_rcec(struct pci_dev *rcec) { }
#ifdef CONFIG_CXL_RAS
bool is_internal_error(struct aer_err_info *info);
+bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info);
+void cxl_forward_error(struct pci_dev *pdev, struct aer_err_info *info);
#else
static inline bool is_internal_error(struct aer_err_info *info) { return false; }
+static inline bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info) { return false; }
+static inline void cxl_forward_error(struct pci_dev *pdev, struct aer_err_info *info) { }
#endif
#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
index 970e7cbc5b34..72992b3ea417 100644
--- a/drivers/pci/pcie/Makefile
+++ b/drivers/pci/pcie/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o bwctrl.o
obj-y += aspm.o
obj-$(CONFIG_PCIEAER) += aer.o err.o tlp.o
obj-$(CONFIG_CXL_RCH_RAS) += aer_cxl_rch.o
+obj-$(CONFIG_CXL_RAS) += aer_cxl_vh.o
obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o
obj-$(CONFIG_PCIE_PME) += pme.o
obj-$(CONFIG_PCIE_DPC) += dpc.o
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 6ba8f84add70..ccefbcfe5145 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -1093,8 +1093,6 @@ static bool find_source_device(struct pci_dev *parent,
return true;
}
-#ifdef CONFIG_CXL_RAS
-
/**
* pci_aer_unmask_internal_errors - unmask internal errors
* @dev: pointer to the pci_dev data structure
@@ -1120,24 +1118,6 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(pci_aer_unmask_internal_errors);
-bool cxl_error_is_native(struct pci_dev *dev)
-{
- struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
-
- return (pcie_ports_native || host->native_aer);
-}
-EXPORT_SYMBOL_NS_GPL(cxl_error_is_native, "CXL");
-
-bool is_internal_error(struct aer_err_info *info)
-{
- if (info->severity == AER_CORRECTABLE)
- return info->status & PCI_ERR_COR_INTERNAL;
-
- return info->status & PCI_ERR_UNC_INTN;
-}
-EXPORT_SYMBOL_NS_GPL(is_internal_error, "CXL");
-#endif /* CONFIG_CXL_RAS */
-
/**
* pci_aer_handle_error - handle logging error into an event log
* @dev: pointer to pci_dev data structure of error source device
@@ -1174,7 +1154,10 @@ static void pci_aer_handle_error(struct pci_dev *dev, struct aer_err_info *info)
static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info)
{
cxl_rch_handle_error(dev, info);
- pci_aer_handle_error(dev, info);
+ if (is_cxl_error(dev, info))
+ cxl_forward_error(dev, info);
+ else
+ pci_aer_handle_error(dev, info);
pci_dev_put(dev);
}
diff --git a/drivers/pci/pcie/aer_cxl_vh.c b/drivers/pci/pcie/aer_cxl_vh.c
new file mode 100644
index 000000000000..8c0979299446
--- /dev/null
+++ b/drivers/pci/pcie/aer_cxl_vh.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2025 AMD Corporation. All rights reserved. */
+
+#include <linux/pci.h>
+#include <linux/aer.h>
+#include <linux/pci.h>
+#include <linux/bitfield.h>
+#include <linux/kfifo.h>
+#include "../pci.h"
+
+#define CXL_ERROR_SOURCES_MAX 128
+
+struct cxl_proto_err_kfifo {
+ struct work_struct *work;
+ struct rw_semaphore rw_sema;
+ DECLARE_KFIFO(fifo, struct cxl_proto_err_work_data,
+ CXL_ERROR_SOURCES_MAX);
+};
+
+static struct cxl_proto_err_kfifo cxl_proto_err_kfifo = {
+ .rw_sema = __RWSEM_INITIALIZER(cxl_proto_err_kfifo.rw_sema)
+};
+
+bool cxl_error_is_native(struct pci_dev *dev)
+{
+ struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
+
+ return (pcie_ports_native || host->native_aer);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_error_is_native, "CXL");
+
+bool is_internal_error(struct aer_err_info *info)
+{
+ if (info->severity == AER_CORRECTABLE)
+ return info->status & PCI_ERR_COR_INTERNAL;
+
+ return info->status & PCI_ERR_UNC_INTN;
+}
+EXPORT_SYMBOL_NS_GPL(is_internal_error, "CXL");
+
+bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
+{
+ if (!info || !info->is_cxl)
+ return false;
+
+ if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT)
+ return false;
+
+ return is_internal_error(info);
+}
+EXPORT_SYMBOL_NS_GPL(is_cxl_error, "CXL");
+
+void cxl_forward_error(struct pci_dev *pdev, struct aer_err_info *info)
+{
+ struct cxl_proto_err_work_data wd = (struct cxl_proto_err_work_data) {
+ .severity = info->severity,
+ .pdev = pdev
+ };
+
+ guard(rwsem_write)(&cxl_proto_err_kfifo.rw_sema);
+
+ if (!cxl_proto_err_kfifo.work) {
+ dev_warn_once(&pdev->dev, "CXL driver is not registered for kfifo");
+ return;
+ }
+
+ if (!kfifo_put(&cxl_proto_err_kfifo.fifo, wd)) {
+ dev_err_ratelimited(&pdev->dev, "CXL kfifo overflow\n");
+ return;
+ }
+
+ schedule_work(cxl_proto_err_kfifo.work);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_forward_error, "CXL");
+
+void cxl_register_proto_err_work(struct work_struct *work)
+{
+ guard(rwsem_write)(&cxl_proto_err_kfifo.rw_sema);
+ cxl_proto_err_kfifo.work = work;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_register_proto_err_work, "CXL");
+
+void cxl_unregister_proto_err_work(void)
+{
+ guard(rwsem_write)(&cxl_proto_err_kfifo.rw_sema);
+ cxl_proto_err_kfifo.work = NULL;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_unregister_proto_err_work, "CXL");
+
+int cxl_proto_err_kfifo_get(struct cxl_proto_err_work_data *wd)
+{
+ guard(rwsem_read)(&cxl_proto_err_kfifo.rw_sema);
+ return kfifo_get(&cxl_proto_err_kfifo.fifo, wd);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_proto_err_kfifo_get, "CXL");
diff --git a/include/linux/aer.h b/include/linux/aer.h
index 2ef820563996..6b2c87d1b5b6 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -10,6 +10,7 @@
#include <linux/errno.h>
#include <linux/types.h>
+#include <linux/workqueue_types.h>
#define AER_NONFATAL 0
#define AER_FATAL 1
@@ -53,6 +54,16 @@ struct aer_capability_regs {
u16 uncor_err_source;
};
+/**
+ * struct cxl_proto_err_work_data - Error information used in CXL error handling
+ * @severity: AER severity
+ * @pdev: PCI device detecting the error
+ */
+struct cxl_proto_err_work_data {
+ int severity;
+ struct pci_dev *pdev;
+};
+
#if defined(CONFIG_PCIEAER)
int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
int pcie_aer_is_native(struct pci_dev *dev);
@@ -68,8 +79,14 @@ static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
#ifdef CONFIG_CXL_RAS
bool cxl_error_is_native(struct pci_dev *dev);
+int cxl_proto_err_kfifo_get(struct cxl_proto_err_work_data *wd);
+void cxl_register_proto_err_work(struct work_struct *work);
+void cxl_unregister_proto_err_work(void);
#else
static inline bool cxl_error_is_native(struct pci_dev *dev) { return false; }
+static inline int cxl_proto_err_kfifo_get(struct cxl_proto_err_work_data *wd) { return 0; }
+static inline void cxl_register_proto_err_work(struct work_struct *work) { }
+static inline void cxl_unregister_proto_err_work(void) { }
#endif
void pci_print_aer(struct pci_dev *dev, int aer_severity,
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 18/25] CXL/AER: Introduce aer_cxl_vh.c in AER driver for forwarding CXL errors
2025-09-25 22:34 ` [PATCH v12 18/25] CXL/AER: Introduce aer_cxl_vh.c in AER driver for forwarding CXL errors Terry Bowman
@ 2025-09-26 22:56 ` Dave Jiang
2025-10-03 20:12 ` Cheatham, Benjamin
1 sibling, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-26 22:56 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> CXL virtual hierarchy (VH) RAS handling for CXL Port devices will be added
> soon. This requires a notification mechanism for the AER driver to share
> the AER interrupt with the CXL driver. The notification will be used as an
> indication for the CXL drivers to handle and log the CXL RAS errors.
>
> Note, 'CXL protocol error' terminology will refer to CXL VH and not
> CXL RCH errors unless specifically noted going forward.
>
> Introduce a new file in the AER driver to handle the CXL protocol errors
> named pci/pcie/aer_cxl_vh.c.
>
> Add a kfifo work queue to be used by the AER and CXL drivers. The AER
> driver will be the sole kfifo producer adding work and the cxl_core will be
> the sole kfifo consumer removing work. Add the boilerplate kfifo support.
> Encapsulate the kfifo, RW semaphore, and work pointer in a single structure.
>
> Add CXL work queue handler registration functions in the AER driver. Export
> the functions allowing CXL driver to access. Implement registration
> functions for the CXL driver to assign or clear the work handler function.
> Synchronize accesses using the RW semaphore.
>
> Introduce 'struct cxl_proto_err_work_data' to serve as the kfifo work data.
> This will contain a reference to the erring PCI device and the error
> severity. This will be used when the work is dequeued by the cxl_core driver.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> ---
>
> Changes in v11->v12:
> - Rename drivers/pci/pcie/cxl_aer.c to drivers/pci/pcie/aer_cxl_vh.c (Lukas)
>
> Changes in v10->v11:
> - cxl_error_detected() - Change handlers' scoped_guard() to guard() (Jonathan)
> - cxl_error_detected() - Remove extra line (Shiju)
> - Changes moved to core/ras.c (Terry)
> - cxl_error_detected(), remove 'ue' and return with function call. (Jonathan)
> - Remove extra space in documentation for PCI_ERS_RESULT_PANIC definition
> - Move #include "pci.h from cxl.h to core.h (Terry)
> - Remove unnecessary includes of cxl.h and core.h in mem.c (Terry)
> ---
> drivers/pci/pci.h | 4 ++
> drivers/pci/pcie/Makefile | 1 +
> drivers/pci/pcie/aer.c | 25 ++-------
> drivers/pci/pcie/aer_cxl_vh.c | 95 +++++++++++++++++++++++++++++++++++
> include/linux/aer.h | 17 +++++++
> 5 files changed, 121 insertions(+), 21 deletions(-)
> create mode 100644 drivers/pci/pcie/aer_cxl_vh.c
>
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index f7631f40e57c..22e8f9a18a09 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -1234,8 +1234,12 @@ static inline void cxl_rch_enable_rcec(struct pci_dev *rcec) { }
>
> #ifdef CONFIG_CXL_RAS
> bool is_internal_error(struct aer_err_info *info);
> +bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info);
> +void cxl_forward_error(struct pci_dev *pdev, struct aer_err_info *info);
> #else
> static inline bool is_internal_error(struct aer_err_info *info) { return false; }
> +static inline bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info) { return false; }
> +static inline void cxl_forward_error(struct pci_dev *pdev, struct aer_err_info *info) { }
> #endif
>
> #endif /* DRIVERS_PCI_H */
> diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
> index 970e7cbc5b34..72992b3ea417 100644
> --- a/drivers/pci/pcie/Makefile
> +++ b/drivers/pci/pcie/Makefile
> @@ -9,6 +9,7 @@ obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o bwctrl.o
> obj-y += aspm.o
> obj-$(CONFIG_PCIEAER) += aer.o err.o tlp.o
> obj-$(CONFIG_CXL_RCH_RAS) += aer_cxl_rch.o
> +obj-$(CONFIG_CXL_RAS) += aer_cxl_vh.o
> obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o
> obj-$(CONFIG_PCIE_PME) += pme.o
> obj-$(CONFIG_PCIE_DPC) += dpc.o
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index 6ba8f84add70..ccefbcfe5145 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -1093,8 +1093,6 @@ static bool find_source_device(struct pci_dev *parent,
> return true;
> }
>
> -#ifdef CONFIG_CXL_RAS
> -
> /**
> * pci_aer_unmask_internal_errors - unmask internal errors
> * @dev: pointer to the pci_dev data structure
> @@ -1120,24 +1118,6 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev)
> }
> EXPORT_SYMBOL_GPL(pci_aer_unmask_internal_errors);
>
> -bool cxl_error_is_native(struct pci_dev *dev)
> -{
> - struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
> -
> - return (pcie_ports_native || host->native_aer);
> -}
> -EXPORT_SYMBOL_NS_GPL(cxl_error_is_native, "CXL");
> -
> -bool is_internal_error(struct aer_err_info *info)
> -{
> - if (info->severity == AER_CORRECTABLE)
> - return info->status & PCI_ERR_COR_INTERNAL;
> -
> - return info->status & PCI_ERR_UNC_INTN;
> -}
> -EXPORT_SYMBOL_NS_GPL(is_internal_error, "CXL");
> -#endif /* CONFIG_CXL_RAS */
> -
> /**
> * pci_aer_handle_error - handle logging error into an event log
> * @dev: pointer to pci_dev data structure of error source device
> @@ -1174,7 +1154,10 @@ static void pci_aer_handle_error(struct pci_dev *dev, struct aer_err_info *info)
> static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info)
> {
> cxl_rch_handle_error(dev, info);
> - pci_aer_handle_error(dev, info);
> + if (is_cxl_error(dev, info))
> + cxl_forward_error(dev, info);
> + else
> + pci_aer_handle_error(dev, info);
> pci_dev_put(dev);
> }
>
> diff --git a/drivers/pci/pcie/aer_cxl_vh.c b/drivers/pci/pcie/aer_cxl_vh.c
> new file mode 100644
> index 000000000000..8c0979299446
> --- /dev/null
> +++ b/drivers/pci/pcie/aer_cxl_vh.c
> @@ -0,0 +1,95 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright(c) 2025 AMD Corporation. All rights reserved. */
> +
> +#include <linux/pci.h>
> +#include <linux/aer.h>
> +#include <linux/pci.h>
> +#include <linux/bitfield.h>
> +#include <linux/kfifo.h>
> +#include "../pci.h"
> +
> +#define CXL_ERROR_SOURCES_MAX 128
> +
> +struct cxl_proto_err_kfifo {
> + struct work_struct *work;
> + struct rw_semaphore rw_sema;
> + DECLARE_KFIFO(fifo, struct cxl_proto_err_work_data,
> + CXL_ERROR_SOURCES_MAX);
> +};
> +
> +static struct cxl_proto_err_kfifo cxl_proto_err_kfifo = {
> + .rw_sema = __RWSEM_INITIALIZER(cxl_proto_err_kfifo.rw_sema)
> +};
> +
> +bool cxl_error_is_native(struct pci_dev *dev)
> +{
> + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
> +
> + return (pcie_ports_native || host->native_aer);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_error_is_native, "CXL");
> +
> +bool is_internal_error(struct aer_err_info *info)
> +{
> + if (info->severity == AER_CORRECTABLE)
> + return info->status & PCI_ERR_COR_INTERNAL;
> +
> + return info->status & PCI_ERR_UNC_INTN;
> +}
> +EXPORT_SYMBOL_NS_GPL(is_internal_error, "CXL");
> +
> +bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
> +{
> + if (!info || !info->is_cxl)
> + return false;
> +
> + if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT)
> + return false;
> +
> + return is_internal_error(info);
> +}
> +EXPORT_SYMBOL_NS_GPL(is_cxl_error, "CXL");
> +
> +void cxl_forward_error(struct pci_dev *pdev, struct aer_err_info *info)
> +{
> + struct cxl_proto_err_work_data wd = (struct cxl_proto_err_work_data) {
> + .severity = info->severity,
> + .pdev = pdev
> + };
> +
> + guard(rwsem_write)(&cxl_proto_err_kfifo.rw_sema);
> +
> + if (!cxl_proto_err_kfifo.work) {
> + dev_warn_once(&pdev->dev, "CXL driver is not registered for kfifo");
> + return;
> + }
> +
> + if (!kfifo_put(&cxl_proto_err_kfifo.fifo, wd)) {
> + dev_err_ratelimited(&pdev->dev, "CXL kfifo overflow\n");
> + return;
> + }
> +
> + schedule_work(cxl_proto_err_kfifo.work);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_forward_error, "CXL");
> +
> +void cxl_register_proto_err_work(struct work_struct *work)
> +{
> + guard(rwsem_write)(&cxl_proto_err_kfifo.rw_sema);
> + cxl_proto_err_kfifo.work = work;
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_register_proto_err_work, "CXL");
> +
> +void cxl_unregister_proto_err_work(void)
> +{
> + guard(rwsem_write)(&cxl_proto_err_kfifo.rw_sema);
> + cxl_proto_err_kfifo.work = NULL;
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_unregister_proto_err_work, "CXL");
> +
> +int cxl_proto_err_kfifo_get(struct cxl_proto_err_work_data *wd)
> +{
> + guard(rwsem_read)(&cxl_proto_err_kfifo.rw_sema);
> + return kfifo_get(&cxl_proto_err_kfifo.fifo, wd);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_proto_err_kfifo_get, "CXL");
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index 2ef820563996..6b2c87d1b5b6 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -10,6 +10,7 @@
>
> #include <linux/errno.h>
> #include <linux/types.h>
> +#include <linux/workqueue_types.h>
>
> #define AER_NONFATAL 0
> #define AER_FATAL 1
> @@ -53,6 +54,16 @@ struct aer_capability_regs {
> u16 uncor_err_source;
> };
>
> +/**
> + * struct cxl_proto_err_work_data - Error information used in CXL error handling
> + * @severity: AER severity
> + * @pdev: PCI device detecting the error
> + */
> +struct cxl_proto_err_work_data {
> + int severity;
> + struct pci_dev *pdev;
> +};
> +
> #if defined(CONFIG_PCIEAER)
> int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
> int pcie_aer_is_native(struct pci_dev *dev);
> @@ -68,8 +79,14 @@ static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
>
> #ifdef CONFIG_CXL_RAS
> bool cxl_error_is_native(struct pci_dev *dev);
> +int cxl_proto_err_kfifo_get(struct cxl_proto_err_work_data *wd);
> +void cxl_register_proto_err_work(struct work_struct *work);
> +void cxl_unregister_proto_err_work(void);
> #else
> static inline bool cxl_error_is_native(struct pci_dev *dev) { return false; }
> +static inline int cxl_proto_err_kfifo_get(struct cxl_proto_err_work_data *wd) { return 0; }
> +static inline void cxl_register_proto_err_work(struct work_struct *work) { }
> +static inline void cxl_unregister_proto_err_work(void) { }
> #endif
>
> void pci_print_aer(struct pci_dev *dev, int aer_severity,
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 18/25] CXL/AER: Introduce aer_cxl_vh.c in AER driver for forwarding CXL errors
2025-09-25 22:34 ` [PATCH v12 18/25] CXL/AER: Introduce aer_cxl_vh.c in AER driver for forwarding CXL errors Terry Bowman
2025-09-26 22:56 ` Dave Jiang
@ 2025-10-03 20:12 ` Cheatham, Benjamin
1 sibling, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:12 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
[snip]
> +
> +void cxl_forward_error(struct pci_dev *pdev, struct aer_err_info *info)
> +{
> + struct cxl_proto_err_work_data wd = (struct cxl_proto_err_work_data) {
> + .severity = info->severity,
> + .pdev = pdev
> + };
> +
> + guard(rwsem_write)(&cxl_proto_err_kfifo.rw_sema);
> +
> + if (!cxl_proto_err_kfifo.work) {
> + dev_warn_once(&pdev->dev, "CXL driver is not registered for kfifo");
I don't think this is a very useful error message to an end user. Maybe something like
"CXL driver is not registered for error forwarding" instead?
> + return;
> + }
> +
> + if (!kfifo_put(&cxl_proto_err_kfifo.fifo, wd)) {
> + dev_err_ratelimited(&pdev->dev, "CXL kfifo overflow\n");
Less sure about this one, since it's an actual error with the kfifo. May want to mention
it's the CXL AER kfifo just in case another kfifo comes along in the CXL driver.
> + return;
> + }
> +
> + schedule_work(cxl_proto_err_kfifo.work);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_forward_error, "CXL");
> +
> +void cxl_register_proto_err_work(struct work_struct *work)
> +{
> + guard(rwsem_write)(&cxl_proto_err_kfifo.rw_sema);
> + cxl_proto_err_kfifo.work = work;
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_register_proto_err_work, "CXL");
> +
> +void cxl_unregister_proto_err_work(void)
> +{
> + guard(rwsem_write)(&cxl_proto_err_kfifo.rw_sema);
> + cxl_proto_err_kfifo.work = NULL;
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_unregister_proto_err_work, "CXL");
> +
> +int cxl_proto_err_kfifo_get(struct cxl_proto_err_work_data *wd)
> +{
> + guard(rwsem_read)(&cxl_proto_err_kfifo.rw_sema);
> + return kfifo_get(&cxl_proto_err_kfifo.fifo, wd);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_proto_err_kfifo_get, "CXL");
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index 2ef820563996..6b2c87d1b5b6 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -10,6 +10,7 @@
>
> #include <linux/errno.h>
> #include <linux/types.h>
> +#include <linux/workqueue_types.h>
>
> #define AER_NONFATAL 0
> #define AER_FATAL 1
> @@ -53,6 +54,16 @@ struct aer_capability_regs {
> u16 uncor_err_source;
> };
>
> +/**
> + * struct cxl_proto_err_work_data - Error information used in CXL error handling
> + * @severity: AER severity
> + * @pdev: PCI device detecting the error
> + */
> +struct cxl_proto_err_work_data {
> + int severity;
> + struct pci_dev *pdev;
> +};
> +
> #if defined(CONFIG_PCIEAER)
> int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
> int pcie_aer_is_native(struct pci_dev *dev);
> @@ -68,8 +79,14 @@ static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
>
> #ifdef CONFIG_CXL_RAS
> bool cxl_error_is_native(struct pci_dev *dev);
> +int cxl_proto_err_kfifo_get(struct cxl_proto_err_work_data *wd);
> +void cxl_register_proto_err_work(struct work_struct *work);
> +void cxl_unregister_proto_err_work(void);
> #else
> static inline bool cxl_error_is_native(struct pci_dev *dev) { return false; }
> +static inline int cxl_proto_err_kfifo_get(struct cxl_proto_err_work_data *wd) { return 0; }
> +static inline void cxl_register_proto_err_work(struct work_struct *work) { }
> +static inline void cxl_unregister_proto_err_work(void) { }
> #endif
>
> void pci_print_aer(struct pci_dev *dev, int aer_severity,
Feels weird to add all this plumbing and then it goes unused. Assuming it's not a heavy lift,
I would like to see at the CXL driver register stubs at least.
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 19/25] cxl: Introduce cxl_pci_drv_bound() to check for bound driver
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (17 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 18/25] CXL/AER: Introduce aer_cxl_vh.c in AER driver for forwarding CXL errors Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-26 23:02 ` Dave Jiang
` (2 more replies)
2025-09-25 22:34 ` [PATCH v12 20/25] PCI/AER: Dequeue forwarded CXL error Terry Bowman
` (5 subsequent siblings)
24 siblings, 3 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
CXL devices handle protocol errors via driver-specific callbacks rather
than the generic pci_driver::err_handlers by default. The callbacks are
implemented in the cxl_pci driver and are not part of struct pci_driver, so
cxl_core must verify that a device is actually bound to the cxl_pci
module's driver before invoking the callbacks (the device could be bound
to another driver, e.g. VFIO).
However, cxl_core can not reference symbols in the cxl_pci module because
it creates a circular dependency. This prevents cxl_core from checking the
EP's bound driver and calling the callbacks.
To fix this, move drivers/cxl/pci.c into drivers/cxl/core/pci_drv.c and
build it as part of the cxl_core module. Compile into cxl_core using
CXL_PCI and CXL_CORE Kconfig dependencies. This removes the standalone cxl_pci
module, consolidates the cxl_pci driver code into cxl_core, and eliminates
the circular dependency so cxl_core can safely perform bound-driver checks
and invoke the CXL PCI callbacks.
Introduce cxl_pci_drv_bound() to return boolean depending on if the PCI EP
parameter is bound to a CXL driver instance. This will be used in future
patch when dequeuing work from the kfifo.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
Changes in v11 -> v12:
- New patch
---
drivers/cxl/Kconfig | 6 +++---
drivers/cxl/Makefile | 2 --
drivers/cxl/core/Makefile | 1 +
drivers/cxl/core/core.h | 9 +++++++++
drivers/cxl/{pci.c => core/pci_drv.c} | 16 ++++++++--------
drivers/cxl/core/port.c | 3 +++
6 files changed, 24 insertions(+), 13 deletions(-)
rename drivers/cxl/{pci.c => core/pci_drv.c} (99%)
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 028201e24523..9ee76bae02d5 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -20,7 +20,7 @@ menuconfig CXL_BUS
if CXL_BUS
config CXL_PCI
- tristate "PCI manageability"
+ bool "PCI manageability"
default CXL_BUS
help
The CXL specification defines a "CXL memory device" sub-class in the
@@ -29,12 +29,12 @@ config CXL_PCI
memory to be mapped into the system address map (Host-managed Device
Memory (HDM)).
- Say 'y/m' to enable a driver that will attach to CXL memory expander
+ Say 'y' to enable a driver that will attach to CXL memory expander
devices enumerated by the memory device class code for configuration
and management primarily via the mailbox interface. See Chapter 2.3
Type 3 CXL Device in the CXL 2.0 specification for more details.
- If unsure say 'm'.
+ If unsure say 'y'.
config CXL_MEM_RAW_COMMANDS
bool "RAW Command Interface for Memory Devices"
diff --git a/drivers/cxl/Makefile b/drivers/cxl/Makefile
index 2caa90fa4bf2..ff6add88b6ae 100644
--- a/drivers/cxl/Makefile
+++ b/drivers/cxl/Makefile
@@ -12,10 +12,8 @@ obj-$(CONFIG_CXL_PORT) += cxl_port.o
obj-$(CONFIG_CXL_ACPI) += cxl_acpi.o
obj-$(CONFIG_CXL_PMEM) += cxl_pmem.o
obj-$(CONFIG_CXL_MEM) += cxl_mem.o
-obj-$(CONFIG_CXL_PCI) += cxl_pci.o
cxl_port-y := port.o
cxl_acpi-y := acpi.o
cxl_pmem-y := pmem.o security.o
cxl_mem-y := mem.o
-cxl_pci-y := pci.o
diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile
index b2930cc54f8b..91f43c3f2292 100644
--- a/drivers/cxl/core/Makefile
+++ b/drivers/cxl/core/Makefile
@@ -20,3 +20,4 @@ cxl_core-$(CONFIG_CXL_MCE) += mce.o
cxl_core-$(CONFIG_CXL_FEATURES) += features.o
cxl_core-$(CONFIG_CXL_EDAC_MEM_FEATURES) += edac.o
cxl_core-$(CONFIG_CXL_RAS) += ras.o
+cxl_core-$(CONFIG_CXL_PCI) += pci_drv.o
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 74c64d458f12..9ceff8acf844 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -202,4 +202,13 @@ int cxl_set_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,
u16 *return_code);
#endif
+#ifdef CONFIG_CXL_PCI
+bool cxl_pci_drv_bound(struct pci_dev *pdev);
+int cxl_pci_driver_init(void);
+void cxl_pci_driver_exit(void);
+#else
+static inline bool cxl_pci_drv_bound(struct pci_dev *pdev) { return false; };
+static inline int cxl_pci_driver_init(void) { return 0; }
+static inline void cxl_pci_driver_exit(void) { }
+#endif
#endif /* __CXL_CORE_H__ */
diff --git a/drivers/cxl/pci.c b/drivers/cxl/core/pci_drv.c
similarity index 99%
rename from drivers/cxl/pci.c
rename to drivers/cxl/core/pci_drv.c
index 71fb8709081e..746b5017d336 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/core/pci_drv.c
@@ -1132,6 +1132,12 @@ static struct pci_driver cxl_pci_driver = {
},
};
+bool cxl_pci_drv_bound(struct pci_dev *pdev)
+{
+ return (pdev->driver == &cxl_pci_driver);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_pci_drv_bound, "CXL");
+
#define CXL_EVENT_HDR_FLAGS_REC_SEVERITY GENMASK(1, 0)
static void cxl_handle_cper_event(enum cxl_event_type ev_type,
struct cxl_cper_event_rec *rec)
@@ -1178,7 +1184,7 @@ static void cxl_cper_work_fn(struct work_struct *work)
}
static DECLARE_WORK(cxl_cper_work, cxl_cper_work_fn);
-static int __init cxl_pci_driver_init(void)
+int __init cxl_pci_driver_init(void)
{
int rc;
@@ -1193,15 +1199,9 @@ static int __init cxl_pci_driver_init(void)
return rc;
}
-static void __exit cxl_pci_driver_exit(void)
+void cxl_pci_driver_exit(void)
{
cxl_cper_unregister_work(&cxl_cper_work);
cancel_work_sync(&cxl_cper_work);
pci_unregister_driver(&cxl_pci_driver);
}
-
-module_init(cxl_pci_driver_init);
-module_exit(cxl_pci_driver_exit);
-MODULE_DESCRIPTION("CXL: PCI manageability");
-MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS("CXL");
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index bd4be046888a..56fa4ac33e8b 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -2502,6 +2502,8 @@ static __init int cxl_core_init(void)
if (rc)
goto err_ras;
+ cxl_pci_driver_init();
+
return 0;
err_ras:
@@ -2517,6 +2519,7 @@ static __init int cxl_core_init(void)
static void cxl_core_exit(void)
{
+ cxl_pci_driver_exit();
cxl_ras_exit();
cxl_region_exit();
bus_unregister(&cxl_bus_type);
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 19/25] cxl: Introduce cxl_pci_drv_bound() to check for bound driver
2025-09-25 22:34 ` [PATCH v12 19/25] cxl: Introduce cxl_pci_drv_bound() to check for bound driver Terry Bowman
@ 2025-09-26 23:02 ` Dave Jiang
2025-10-02 12:27 ` Jonathan Cameron
2025-10-03 20:12 ` Cheatham, Benjamin
2 siblings, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-26 23:02 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> CXL devices handle protocol errors via driver-specific callbacks rather
> than the generic pci_driver::err_handlers by default. The callbacks are
> implemented in the cxl_pci driver and are not part of struct pci_driver, so
> cxl_core must verify that a device is actually bound to the cxl_pci
> module's driver before invoking the callbacks (the device could be bound
> to another driver, e.g. VFIO).
>
> However, cxl_core can not reference symbols in the cxl_pci module because
> it creates a circular dependency. This prevents cxl_core from checking the
> EP's bound driver and calling the callbacks.
>
> To fix this, move drivers/cxl/pci.c into drivers/cxl/core/pci_drv.c and
> build it as part of the cxl_core module. Compile into cxl_core using
> CXL_PCI and CXL_CORE Kconfig dependencies. This removes the standalone cxl_pci
> module, consolidates the cxl_pci driver code into cxl_core, and eliminates
> the circular dependency so cxl_core can safely perform bound-driver checks
> and invoke the CXL PCI callbacks.
>
> Introduce cxl_pci_drv_bound() to return boolean depending on if the PCI EP
> parameter is bound to a CXL driver instance. This will be used in future
> patch when dequeuing work from the kfifo.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> ---
>
> Changes in v11 -> v12:
> - New patch
> ---
> drivers/cxl/Kconfig | 6 +++---
> drivers/cxl/Makefile | 2 --
> drivers/cxl/core/Makefile | 1 +
> drivers/cxl/core/core.h | 9 +++++++++
> drivers/cxl/{pci.c => core/pci_drv.c} | 16 ++++++++--------
> drivers/cxl/core/port.c | 3 +++
> 6 files changed, 24 insertions(+), 13 deletions(-)
> rename drivers/cxl/{pci.c => core/pci_drv.c} (99%)
>
> diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
> index 028201e24523..9ee76bae02d5 100644
> --- a/drivers/cxl/Kconfig
> +++ b/drivers/cxl/Kconfig
> @@ -20,7 +20,7 @@ menuconfig CXL_BUS
> if CXL_BUS
>
> config CXL_PCI
> - tristate "PCI manageability"
> + bool "PCI manageability"
> default CXL_BUS
> help
> The CXL specification defines a "CXL memory device" sub-class in the
> @@ -29,12 +29,12 @@ config CXL_PCI
> memory to be mapped into the system address map (Host-managed Device
> Memory (HDM)).
>
> - Say 'y/m' to enable a driver that will attach to CXL memory expander
> + Say 'y' to enable a driver that will attach to CXL memory expander
> devices enumerated by the memory device class code for configuration
> and management primarily via the mailbox interface. See Chapter 2.3
> Type 3 CXL Device in the CXL 2.0 specification for more details.
>
> - If unsure say 'm'.
> + If unsure say 'y'.
>
> config CXL_MEM_RAW_COMMANDS
> bool "RAW Command Interface for Memory Devices"
> diff --git a/drivers/cxl/Makefile b/drivers/cxl/Makefile
> index 2caa90fa4bf2..ff6add88b6ae 100644
> --- a/drivers/cxl/Makefile
> +++ b/drivers/cxl/Makefile
> @@ -12,10 +12,8 @@ obj-$(CONFIG_CXL_PORT) += cxl_port.o
> obj-$(CONFIG_CXL_ACPI) += cxl_acpi.o
> obj-$(CONFIG_CXL_PMEM) += cxl_pmem.o
> obj-$(CONFIG_CXL_MEM) += cxl_mem.o
> -obj-$(CONFIG_CXL_PCI) += cxl_pci.o
>
> cxl_port-y := port.o
> cxl_acpi-y := acpi.o
> cxl_pmem-y := pmem.o security.o
> cxl_mem-y := mem.o
> -cxl_pci-y := pci.o
> diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile
> index b2930cc54f8b..91f43c3f2292 100644
> --- a/drivers/cxl/core/Makefile
> +++ b/drivers/cxl/core/Makefile
> @@ -20,3 +20,4 @@ cxl_core-$(CONFIG_CXL_MCE) += mce.o
> cxl_core-$(CONFIG_CXL_FEATURES) += features.o
> cxl_core-$(CONFIG_CXL_EDAC_MEM_FEATURES) += edac.o
> cxl_core-$(CONFIG_CXL_RAS) += ras.o
> +cxl_core-$(CONFIG_CXL_PCI) += pci_drv.o
> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
> index 74c64d458f12..9ceff8acf844 100644
> --- a/drivers/cxl/core/core.h
> +++ b/drivers/cxl/core/core.h
> @@ -202,4 +202,13 @@ int cxl_set_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,
> u16 *return_code);
> #endif
>
> +#ifdef CONFIG_CXL_PCI
> +bool cxl_pci_drv_bound(struct pci_dev *pdev);
> +int cxl_pci_driver_init(void);
> +void cxl_pci_driver_exit(void);
> +#else
> +static inline bool cxl_pci_drv_bound(struct pci_dev *pdev) { return false; };
> +static inline int cxl_pci_driver_init(void) { return 0; }
> +static inline void cxl_pci_driver_exit(void) { }
> +#endif
> #endif /* __CXL_CORE_H__ */
> diff --git a/drivers/cxl/pci.c b/drivers/cxl/core/pci_drv.c
> similarity index 99%
> rename from drivers/cxl/pci.c
> rename to drivers/cxl/core/pci_drv.c
> index 71fb8709081e..746b5017d336 100644
> --- a/drivers/cxl/pci.c
> +++ b/drivers/cxl/core/pci_drv.c
> @@ -1132,6 +1132,12 @@ static struct pci_driver cxl_pci_driver = {
> },
> };
>
> +bool cxl_pci_drv_bound(struct pci_dev *pdev)
> +{
> + return (pdev->driver == &cxl_pci_driver);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_pci_drv_bound, "CXL");
> +
> #define CXL_EVENT_HDR_FLAGS_REC_SEVERITY GENMASK(1, 0)
> static void cxl_handle_cper_event(enum cxl_event_type ev_type,
> struct cxl_cper_event_rec *rec)
> @@ -1178,7 +1184,7 @@ static void cxl_cper_work_fn(struct work_struct *work)
> }
> static DECLARE_WORK(cxl_cper_work, cxl_cper_work_fn);
>
> -static int __init cxl_pci_driver_init(void)
> +int __init cxl_pci_driver_init(void)
> {
> int rc;
>
> @@ -1193,15 +1199,9 @@ static int __init cxl_pci_driver_init(void)
> return rc;
> }
>
> -static void __exit cxl_pci_driver_exit(void)
> +void cxl_pci_driver_exit(void)
> {
> cxl_cper_unregister_work(&cxl_cper_work);
> cancel_work_sync(&cxl_cper_work);
> pci_unregister_driver(&cxl_pci_driver);
> }
> -
> -module_init(cxl_pci_driver_init);
> -module_exit(cxl_pci_driver_exit);
> -MODULE_DESCRIPTION("CXL: PCI manageability");
> -MODULE_LICENSE("GPL v2");
> -MODULE_IMPORT_NS("CXL");
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index bd4be046888a..56fa4ac33e8b 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -2502,6 +2502,8 @@ static __init int cxl_core_init(void)
> if (rc)
> goto err_ras;
>
> + cxl_pci_driver_init();
> +
> return 0;
>
> err_ras:
> @@ -2517,6 +2519,7 @@ static __init int cxl_core_init(void)
>
> static void cxl_core_exit(void)
> {
> + cxl_pci_driver_exit();
> cxl_ras_exit();
> cxl_region_exit();
> bus_unregister(&cxl_bus_type);
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 19/25] cxl: Introduce cxl_pci_drv_bound() to check for bound driver
2025-09-25 22:34 ` [PATCH v12 19/25] cxl: Introduce cxl_pci_drv_bound() to check for bound driver Terry Bowman
2025-09-26 23:02 ` Dave Jiang
@ 2025-10-02 12:27 ` Jonathan Cameron
2025-10-03 20:12 ` Cheatham, Benjamin
2 siblings, 0 replies; 92+ messages in thread
From: Jonathan Cameron @ 2025-10-02 12:27 UTC (permalink / raw)
To: Terry Bowman
Cc: dave, dave.jiang, alison.schofield, dan.j.williams, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, linux-cxl,
alucerop, ira.weiny, linux-kernel, linux-pci
On Thu, 25 Sep 2025 17:34:34 -0500
Terry Bowman <terry.bowman@amd.com> wrote:
> CXL devices handle protocol errors via driver-specific callbacks rather
> than the generic pci_driver::err_handlers by default. The callbacks are
> implemented in the cxl_pci driver and are not part of struct pci_driver, so
> cxl_core must verify that a device is actually bound to the cxl_pci
> module's driver before invoking the callbacks (the device could be bound
> to another driver, e.g. VFIO).
>
> However, cxl_core can not reference symbols in the cxl_pci module because
> it creates a circular dependency. This prevents cxl_core from checking the
> EP's bound driver and calling the callbacks.
>
> To fix this, move drivers/cxl/pci.c into drivers/cxl/core/pci_drv.c and
> build it as part of the cxl_core module. Compile into cxl_core using
> CXL_PCI and CXL_CORE Kconfig dependencies. This removes the standalone cxl_pci
> module, consolidates the cxl_pci driver code into cxl_core, and eliminates
> the circular dependency so cxl_core can safely perform bound-driver checks
> and invoke the CXL PCI callbacks.
>
> Introduce cxl_pci_drv_bound() to return boolean depending on if the PCI EP
> parameter is bound to a CXL driver instance. This will be used in future
> patch when dequeuing work from the kfifo.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>
Description is nice and clear on the necessity so fair enough.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 19/25] cxl: Introduce cxl_pci_drv_bound() to check for bound driver
2025-09-25 22:34 ` [PATCH v12 19/25] cxl: Introduce cxl_pci_drv_bound() to check for bound driver Terry Bowman
2025-09-26 23:02 ` Dave Jiang
2025-10-02 12:27 ` Jonathan Cameron
@ 2025-10-03 20:12 ` Cheatham, Benjamin
2 siblings, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:12 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny, linux-cxl
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> CXL devices handle protocol errors via driver-specific callbacks rather
> than the generic pci_driver::err_handlers by default. The callbacks are
> implemented in the cxl_pci driver and are not part of struct pci_driver, so
> cxl_core must verify that a device is actually bound to the cxl_pci
> module's driver before invoking the callbacks (the device could be bound
> to another driver, e.g. VFIO).
>
> However, cxl_core can not reference symbols in the cxl_pci module because
> it creates a circular dependency. This prevents cxl_core from checking the
> EP's bound driver and calling the callbacks.
>
> To fix this, move drivers/cxl/pci.c into drivers/cxl/core/pci_drv.c and
> build it as part of the cxl_core module. Compile into cxl_core using
> CXL_PCI and CXL_CORE Kconfig dependencies. This removes the standalone cxl_pci
> module, consolidates the cxl_pci driver code into cxl_core, and eliminates
> the circular dependency so cxl_core can safely perform bound-driver checks
> and invoke the CXL PCI callbacks.
>
> Introduce cxl_pci_drv_bound() to return boolean depending on if the PCI EP
> parameter is bound to a CXL driver instance. This will be used in future
> patch when dequeuing work from the kfifo.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>
> ---
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 20/25] PCI/AER: Dequeue forwarded CXL error
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (18 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 19/25] cxl: Introduce cxl_pci_drv_bound() to check for bound driver Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-26 23:26 ` Dave Jiang
2025-10-03 20:12 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 21/25] CXL/PCI: Introduce CXL Port protocol error handlers Terry Bowman
` (4 subsequent siblings)
24 siblings, 2 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
The AER driver is now designed to forward CXL protocol errors to the CXL
driver. Update the CXL driver with functionality to dequeue the forwarded
CXL error from the kfifo. Also, update the CXL driver to begin the protocol
error handling processing using the work received from the FIFO.
Update function cxl_proto_err_work_fn() to dequeue work forwarded by the
AER service driver. This will begin the CXL protocol error processing with
a call to cxl_handle_proto_error().
Introduce logic to take the SBDF values from 'struct cxl_proto_error_info'
and use in discovering the erring PCI device. The call to pci_get_domain_bus_and_slot()
will return a reference counted 'struct pci_dev *'. This will serve as
reference count to prevent releasing the CXL Endpoint's mapped RAS while
handling the error. Use scope base __free() to put the reference count.
This will change when adding support for CXL port devices in the future.
Implement cxl_handle_proto_error() to differentiate between Restricted CXL
Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
Maintain the existing RCH handling. Export the AER driver's pcie_walk_rcec()
allowing the CXL driver to walk the RCEC's secondary bus.
VH correctable error (CE) processing will call the CXL CE handler. VH
uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
and pci_clean_device_status() used to clean up AER status after handling.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
Changes in v11->v12:
- Add guard for CE case in cxl_handle_proto_error() (Dave)
Changes in v10->v11:
- Reword patch commit message to remove RCiEP details (Jonathan)
- Add #include <linux/bitfield.h> (Terry)
- is_cxl_rcd() - Fix short comment message wrap (Jonathan)
- is_cxl_rcd() - Combine return calls into 1 (Jonathan)
- cxl_handle_proto_error() - Move comment earlier (Jonathan)
- Usse FIELD_GET() in discovering class code (Jonathan)
- Remove BDF from cxl_proto_err_work_data. Use 'struct
pci_dev *' (Dan)
---
drivers/cxl/core/ras.c | 72 ++++++++++++++++++++++++++++++++++-------
drivers/pci/pci.c | 1 +
drivers/pci/pci.h | 7 ----
drivers/pci/pcie/aer.c | 1 +
drivers/pci/pcie/rcec.c | 1 +
include/linux/aer.h | 2 ++
include/linux/pci.h | 9 ++++++
7 files changed, 75 insertions(+), 18 deletions(-)
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 39472d82d586..9acfe24ba3bb 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -117,17 +117,6 @@ static void cxl_cper_prot_err_work_fn(struct work_struct *work)
}
static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
-int cxl_ras_init(void)
-{
- return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
-}
-
-void cxl_ras_exit(void)
-{
- cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work);
- cancel_work_sync(&cxl_cper_prot_err_work);
-}
-
static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base);
static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
@@ -331,6 +320,10 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
}
EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
+static void cxl_do_recovery(struct device *dev)
+{
+}
+
static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
{
void __iomem *addr;
@@ -472,3 +465,60 @@ pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
return rc;
}
EXPORT_SYMBOL_NS_GPL(pci_error_detected, "CXL");
+
+static void cxl_handle_proto_error(struct cxl_proto_err_work_data *err_info)
+{
+ struct pci_dev *pdev = err_info->pdev;
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ struct cxl_memdev *cxlmd = cxlds->cxlmd;
+ struct device *host_dev __free(put_device) = get_device(&cxlmd->dev);
+
+ if (err_info->severity == AER_CORRECTABLE) {
+ int aer = pdev->aer_cap;
+
+ guard(device)(&pdev->dev);
+
+ if (aer)
+ pci_clear_and_set_config_dword(pdev,
+ aer + PCI_ERR_COR_STATUS,
+ 0, PCI_ERR_COR_INTERNAL);
+
+ if (!cxl_pci_drv_bound(pdev))
+ return;
+
+ cxl_cor_error_detected(&cxlmd->dev);
+ pcie_clear_device_status(pdev);
+ } else {
+ cxl_do_recovery(&cxlmd->dev);
+ }
+}
+
+static void cxl_proto_err_work_fn(struct work_struct *work)
+{
+ struct cxl_proto_err_work_data wd;
+
+ while (cxl_proto_err_kfifo_get(&wd))
+ cxl_handle_proto_error(&wd);
+}
+
+static struct work_struct cxl_proto_err_work;
+static DECLARE_WORK(cxl_proto_err_work, cxl_proto_err_work_fn);
+
+int cxl_ras_init(void)
+{
+ if (cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work))
+ pr_err("Failed to initialize CXL RAS CPER\n");
+
+ cxl_register_proto_err_work(&cxl_proto_err_work);
+
+ return 0;
+}
+
+void cxl_ras_exit(void)
+{
+ cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work);
+ cancel_work_sync(&cxl_cper_prot_err_work);
+
+ cxl_unregister_proto_err_work();
+ cancel_work_sync(&cxl_proto_err_work);
+}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 1a4f61caa0db..c8f17233a18e 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
}
+EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
#endif
/**
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 22e8f9a18a09..189b22ab2b1b 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -692,16 +692,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
void pci_rcec_init(struct pci_dev *dev);
void pci_rcec_exit(struct pci_dev *dev);
void pcie_link_rcec(struct pci_dev *rcec);
-void pcie_walk_rcec(struct pci_dev *rcec,
- int (*cb)(struct pci_dev *, void *),
- void *userdata);
#else
static inline void pci_rcec_init(struct pci_dev *dev) { }
static inline void pci_rcec_exit(struct pci_dev *dev) { }
static inline void pcie_link_rcec(struct pci_dev *rcec) { }
-static inline void pcie_walk_rcec(struct pci_dev *rcec,
- int (*cb)(struct pci_dev *, void *),
- void *userdata) { }
#endif
#ifdef CONFIG_PCI_ATS
@@ -1081,7 +1075,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
static inline void pci_no_aer(void) { }
static inline void pci_aer_init(struct pci_dev *d) { }
static inline void pci_aer_exit(struct pci_dev *d) { }
-static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
static inline void pci_save_aer_state(struct pci_dev *dev) { }
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index ccefbcfe5145..e018531f5982 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -288,6 +288,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
if (status)
pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
}
+EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
/**
* pci_aer_raw_clear_status - Clear AER error registers.
diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
index d0bcd141ac9c..fb6cf6449a1d 100644
--- a/drivers/pci/pcie/rcec.c
+++ b/drivers/pci/pcie/rcec.c
@@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
walk_rcec(walk_rcec_helper, &rcec_data);
}
+EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
void pci_rcec_init(struct pci_dev *dev)
{
diff --git a/include/linux/aer.h b/include/linux/aer.h
index 6b2c87d1b5b6..64aef69fb546 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -66,6 +66,7 @@ struct cxl_proto_err_work_data {
#if defined(CONFIG_PCIEAER)
int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
+void pci_aer_clear_fatal_status(struct pci_dev *dev);
int pcie_aer_is_native(struct pci_dev *dev);
void pci_aer_unmask_internal_errors(struct pci_dev *dev);
#else
@@ -73,6 +74,7 @@ static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
{
return -EINVAL;
}
+static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
#endif
diff --git a/include/linux/pci.h b/include/linux/pci.h
index bc3a7b6d0f94..b8e36bde346c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1825,6 +1825,9 @@ extern bool pcie_ports_native;
int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
bool use_lt);
+void pcie_walk_rcec(struct pci_dev *rcec,
+ int (*cb)(struct pci_dev *, void *),
+ void *userdata);
#else
#define pcie_ports_disabled true
#define pcie_ports_native false
@@ -1835,8 +1838,14 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
{
return -EOPNOTSUPP;
}
+
+static inline void pcie_walk_rcec(struct pci_dev *rcec,
+ int (*cb)(struct pci_dev *, void *),
+ void *userdata) { }
#endif
+void pcie_clear_device_status(struct pci_dev *dev);
+
#define PCIE_LINK_STATE_L0S (BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
#define PCIE_LINK_STATE_L1 BIT(2) /* L1 state */
#define PCIE_LINK_STATE_L1_1 BIT(3) /* ASPM L1.1 state */
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 20/25] PCI/AER: Dequeue forwarded CXL error
2025-09-25 22:34 ` [PATCH v12 20/25] PCI/AER: Dequeue forwarded CXL error Terry Bowman
@ 2025-09-26 23:26 ` Dave Jiang
2025-10-03 20:12 ` Cheatham, Benjamin
1 sibling, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-26 23:26 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> The AER driver is now designed to forward CXL protocol errors to the CXL
> driver. Update the CXL driver with functionality to dequeue the forwarded
> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
> error handling processing using the work received from the FIFO.
>
> Update function cxl_proto_err_work_fn() to dequeue work forwarded by the
> AER service driver. This will begin the CXL protocol error processing with
> a call to cxl_handle_proto_error().
>
> Introduce logic to take the SBDF values from 'struct cxl_proto_error_info'
> and use in discovering the erring PCI device. The call to pci_get_domain_bus_and_slot()
> will return a reference counted 'struct pci_dev *'. This will serve as
> reference count to prevent releasing the CXL Endpoint's mapped RAS while
> handling the error. Use scope base __free() to put the reference count.
> This will change when adding support for CXL port devices in the future.
>
> Implement cxl_handle_proto_error() to differentiate between Restricted CXL
> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
> Maintain the existing RCH handling. Export the AER driver's pcie_walk_rcec()
> allowing the CXL driver to walk the RCEC's secondary bus.
>
> VH correctable error (CE) processing will call the CXL CE handler. VH
> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
> and pci_clean_device_status() used to clean up AER status after handling.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> ---
> Changes in v11->v12:
> - Add guard for CE case in cxl_handle_proto_error() (Dave)
>
> Changes in v10->v11:
> - Reword patch commit message to remove RCiEP details (Jonathan)
> - Add #include <linux/bitfield.h> (Terry)
> - is_cxl_rcd() - Fix short comment message wrap (Jonathan)
> - is_cxl_rcd() - Combine return calls into 1 (Jonathan)
> - cxl_handle_proto_error() - Move comment earlier (Jonathan)
> - Usse FIELD_GET() in discovering class code (Jonathan)
> - Remove BDF from cxl_proto_err_work_data. Use 'struct
> pci_dev *' (Dan)
> ---
> drivers/cxl/core/ras.c | 72 ++++++++++++++++++++++++++++++++++-------
> drivers/pci/pci.c | 1 +
> drivers/pci/pci.h | 7 ----
> drivers/pci/pcie/aer.c | 1 +
> drivers/pci/pcie/rcec.c | 1 +
> include/linux/aer.h | 2 ++
> include/linux/pci.h | 9 ++++++
> 7 files changed, 75 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 39472d82d586..9acfe24ba3bb 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -117,17 +117,6 @@ static void cxl_cper_prot_err_work_fn(struct work_struct *work)
> }
> static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>
> -int cxl_ras_init(void)
> -{
> - return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
> -}
> -
> -void cxl_ras_exit(void)
> -{
> - cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work);
> - cancel_work_sync(&cxl_cper_prot_err_work);
> -}
> -
> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base);
> static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
>
> @@ -331,6 +320,10 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
> }
> EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>
> +static void cxl_do_recovery(struct device *dev)
> +{
> +}
> +
> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
> {
> void __iomem *addr;
> @@ -472,3 +465,60 @@ pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
> return rc;
> }
> EXPORT_SYMBOL_NS_GPL(pci_error_detected, "CXL");
> +
> +static void cxl_handle_proto_error(struct cxl_proto_err_work_data *err_info)
> +{
> + struct pci_dev *pdev = err_info->pdev;
> + struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
The pci_dev device lock needs to be held and cxl_pci_drv_bound() needs to be checked before this is called.
> + struct cxl_memdev *cxlmd = cxlds->cxlmd;
> + struct device *host_dev __free(put_device) = get_device(&cxlmd->dev);
> +
> + if (err_info->severity == AER_CORRECTABLE) {
> + int aer = pdev->aer_cap;
> +
> + guard(device)(&pdev->dev);
> +
> + if (aer)
> + pci_clear_and_set_config_dword(pdev,
> + aer + PCI_ERR_COR_STATUS,
> + 0, PCI_ERR_COR_INTERNAL);
> +
> + if (!cxl_pci_drv_bound(pdev))
> + return;
> +
> + cxl_cor_error_detected(&cxlmd->dev);
> + pcie_clear_device_status(pdev);
> + } else {
> + cxl_do_recovery(&cxlmd->dev);
> + }
> +}
> +
> +static void cxl_proto_err_work_fn(struct work_struct *work)
> +{
> + struct cxl_proto_err_work_data wd;
> +
> + while (cxl_proto_err_kfifo_get(&wd))
> + cxl_handle_proto_error(&wd);
> +}
> +
> +static struct work_struct cxl_proto_err_work;
> +static DECLARE_WORK(cxl_proto_err_work, cxl_proto_err_work_fn);
> +
> +int cxl_ras_init(void)
> +{
> + if (cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work))
> + pr_err("Failed to initialize CXL RAS CPER\n");
> +
> + cxl_register_proto_err_work(&cxl_proto_err_work);
> +
> + return 0;
> +}
> +
> +void cxl_ras_exit(void)
> +{
> + cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work);
> + cancel_work_sync(&cxl_cper_prot_err_work);
> +
> + cxl_unregister_proto_err_work();
> + cancel_work_sync(&cxl_proto_err_work);
> +}
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 1a4f61caa0db..c8f17233a18e 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
> pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
> pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
> }
> +EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
> #endif>
> /**
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 22e8f9a18a09..189b22ab2b1b 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -692,16 +692,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
> void pci_rcec_init(struct pci_dev *dev);
> void pci_rcec_exit(struct pci_dev *dev);
> void pcie_link_rcec(struct pci_dev *rcec);
> -void pcie_walk_rcec(struct pci_dev *rcec,
> - int (*cb)(struct pci_dev *, void *),
> - void *userdata);
> #else
> static inline void pci_rcec_init(struct pci_dev *dev) { }
> static inline void pci_rcec_exit(struct pci_dev *dev) { }
> static inline void pcie_link_rcec(struct pci_dev *rcec) { }
> -static inline void pcie_walk_rcec(struct pci_dev *rcec,
> - int (*cb)(struct pci_dev *, void *),
> - void *userdata) { }
> #endif
>
> #ifdef CONFIG_PCI_ATS
> @@ -1081,7 +1075,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
> static inline void pci_no_aer(void) { }
> static inline void pci_aer_init(struct pci_dev *d) { }
> static inline void pci_aer_exit(struct pci_dev *d) { }
> -static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
> static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
> static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
> static inline void pci_save_aer_state(struct pci_dev *dev) { }
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index ccefbcfe5145..e018531f5982 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -288,6 +288,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
> if (status)
> pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
> }
> +EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
Not seeing this being used anywhee. Should this go to a different patch?
>
> /**
> * pci_aer_raw_clear_status - Clear AER error registers.
> diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
> index d0bcd141ac9c..fb6cf6449a1d 100644
> --- a/drivers/pci/pcie/rcec.c
> +++ b/drivers/pci/pcie/rcec.c
> @@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
>
> walk_rcec(walk_rcec_helper, &rcec_data);
> }
> +EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
Not seeing this being used in this patch either.
DJ
>
> void pci_rcec_init(struct pci_dev *dev)
> {
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index 6b2c87d1b5b6..64aef69fb546 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -66,6 +66,7 @@ struct cxl_proto_err_work_data {
>
> #if defined(CONFIG_PCIEAER)
> int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
> +void pci_aer_clear_fatal_status(struct pci_dev *dev);
> int pcie_aer_is_native(struct pci_dev *dev);
> void pci_aer_unmask_internal_errors(struct pci_dev *dev);
> #else
> @@ -73,6 +74,7 @@ static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
> {
> return -EINVAL;
> }
> +static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
> static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
> static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
> #endif
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index bc3a7b6d0f94..b8e36bde346c 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1825,6 +1825,9 @@ extern bool pcie_ports_native;
>
> int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
> bool use_lt);
> +void pcie_walk_rcec(struct pci_dev *rcec,
> + int (*cb)(struct pci_dev *, void *),
> + void *userdata);
> #else
> #define pcie_ports_disabled true
> #define pcie_ports_native false
> @@ -1835,8 +1838,14 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
> {
> return -EOPNOTSUPP;
> }
> +
> +static inline void pcie_walk_rcec(struct pci_dev *rcec,
> + int (*cb)(struct pci_dev *, void *),
> + void *userdata) { }
> #endif
>
> +void pcie_clear_device_status(struct pci_dev *dev);
> +
> #define PCIE_LINK_STATE_L0S (BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
> #define PCIE_LINK_STATE_L1 BIT(2) /* L1 state */
> #define PCIE_LINK_STATE_L1_1 BIT(3) /* ASPM L1.1 state */
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 20/25] PCI/AER: Dequeue forwarded CXL error
2025-09-25 22:34 ` [PATCH v12 20/25] PCI/AER: Dequeue forwarded CXL error Terry Bowman
2025-09-26 23:26 ` Dave Jiang
@ 2025-10-03 20:12 ` Cheatham, Benjamin
2025-10-06 20:17 ` Dave Jiang
1 sibling, 1 reply; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:12 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
[snip]
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 1a4f61caa0db..c8f17233a18e 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
> pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
> pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
> }
> +EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
Probably should just use EXPORT_SYMBOL_GPL() here. Doesn't make sense to export in the CXL namespace
for a non-CXL specific function.
> #endif
>
> /**
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 22e8f9a18a09..189b22ab2b1b 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -692,16 +692,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
> void pci_rcec_init(struct pci_dev *dev);
> void pci_rcec_exit(struct pci_dev *dev);
> void pcie_link_rcec(struct pci_dev *rcec);
> -void pcie_walk_rcec(struct pci_dev *rcec,
> - int (*cb)(struct pci_dev *, void *),
> - void *userdata);
> #else
> static inline void pci_rcec_init(struct pci_dev *dev) { }
> static inline void pci_rcec_exit(struct pci_dev *dev) { }
> static inline void pcie_link_rcec(struct pci_dev *rcec) { }
> -static inline void pcie_walk_rcec(struct pci_dev *rcec,
> - int (*cb)(struct pci_dev *, void *),
> - void *userdata) { }
> #endif
>
> #ifdef CONFIG_PCI_ATS
> @@ -1081,7 +1075,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
> static inline void pci_no_aer(void) { }
> static inline void pci_aer_init(struct pci_dev *d) { }
> static inline void pci_aer_exit(struct pci_dev *d) { }
> -static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
> static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
> static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
> static inline void pci_save_aer_state(struct pci_dev *dev) { }
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index ccefbcfe5145..e018531f5982 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -288,6 +288,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
> if (status)
> pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
> }
> +EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
>
> /**
> * pci_aer_raw_clear_status - Clear AER error registers.
> diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
> index d0bcd141ac9c..fb6cf6449a1d 100644
> --- a/drivers/pci/pcie/rcec.c
> +++ b/drivers/pci/pcie/rcec.c
> @@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
>
> walk_rcec(walk_rcec_helper, &rcec_data);
> }
> +EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
Same thing as above?
>
> void pci_rcec_init(struct pci_dev *dev)
> {
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index 6b2c87d1b5b6..64aef69fb546 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -66,6 +66,7 @@ struct cxl_proto_err_work_data {
>
> #if defined(CONFIG_PCIEAER)
> int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
> +void pci_aer_clear_fatal_status(struct pci_dev *dev);
> int pcie_aer_is_native(struct pci_dev *dev);
> void pci_aer_unmask_internal_errors(struct pci_dev *dev);
> #else
> @@ -73,6 +74,7 @@ static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
> {
> return -EINVAL;
> }
> +static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
> static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
> static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
> #endif
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index bc3a7b6d0f94..b8e36bde346c 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1825,6 +1825,9 @@ extern bool pcie_ports_native;
>
> int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
> bool use_lt);
> +void pcie_walk_rcec(struct pci_dev *rcec,
> + int (*cb)(struct pci_dev *, void *),
> + void *userdata);
> #else
> #define pcie_ports_disabled true
> #define pcie_ports_native false
> @@ -1835,8 +1838,14 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
> {
> return -EOPNOTSUPP;
> }
> +
> +static inline void pcie_walk_rcec(struct pci_dev *rcec,
> + int (*cb)(struct pci_dev *, void *),
> + void *userdata) { }
> #endif
>
> +void pcie_clear_device_status(struct pci_dev *dev);
> +
> #define PCIE_LINK_STATE_L0S (BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
> #define PCIE_LINK_STATE_L1 BIT(2) /* L1 state */
> #define PCIE_LINK_STATE_L1_1 BIT(3) /* ASPM L1.1 state */
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 20/25] PCI/AER: Dequeue forwarded CXL error
2025-10-03 20:12 ` Cheatham, Benjamin
@ 2025-10-06 20:17 ` Dave Jiang
0 siblings, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-10-06 20:17 UTC (permalink / raw)
To: Cheatham, Benjamin, Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 10/3/25 1:12 PM, Cheatham, Benjamin wrote:
> [snip]
>
>> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
>> index 1a4f61caa0db..c8f17233a18e 100644
>> --- a/drivers/pci/pci.c
>> +++ b/drivers/pci/pci.c
>> @@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
>> pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
>> pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
>> }
>> +EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
>
> Probably should just use EXPORT_SYMBOL_GPL() here. Doesn't make sense to export in the CXL namespace
> for a non-CXL specific function.
Typically unless the function is being used somewhere else besides CXL, it's probably good to reside in the CXL namespace. Of course it's up to Bjorn if he wants it different.
DJ
>
>> #endif
>>
>> /**
>> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
>> index 22e8f9a18a09..189b22ab2b1b 100644
>> --- a/drivers/pci/pci.h
>> +++ b/drivers/pci/pci.h
>> @@ -692,16 +692,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
>> void pci_rcec_init(struct pci_dev *dev);
>> void pci_rcec_exit(struct pci_dev *dev);
>> void pcie_link_rcec(struct pci_dev *rcec);
>> -void pcie_walk_rcec(struct pci_dev *rcec,
>> - int (*cb)(struct pci_dev *, void *),
>> - void *userdata);
>> #else
>> static inline void pci_rcec_init(struct pci_dev *dev) { }
>> static inline void pci_rcec_exit(struct pci_dev *dev) { }
>> static inline void pcie_link_rcec(struct pci_dev *rcec) { }
>> -static inline void pcie_walk_rcec(struct pci_dev *rcec,
>> - int (*cb)(struct pci_dev *, void *),
>> - void *userdata) { }
>> #endif
>>
>> #ifdef CONFIG_PCI_ATS
>> @@ -1081,7 +1075,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
>> static inline void pci_no_aer(void) { }
>> static inline void pci_aer_init(struct pci_dev *d) { }
>> static inline void pci_aer_exit(struct pci_dev *d) { }
>> -static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>> static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
>> static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
>> static inline void pci_save_aer_state(struct pci_dev *dev) { }
>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>> index ccefbcfe5145..e018531f5982 100644
>> --- a/drivers/pci/pcie/aer.c
>> +++ b/drivers/pci/pcie/aer.c
>> @@ -288,6 +288,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
>> if (status)
>> pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
>> }
>> +EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
>>
>> /**
>> * pci_aer_raw_clear_status - Clear AER error registers.
>> diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
>> index d0bcd141ac9c..fb6cf6449a1d 100644
>> --- a/drivers/pci/pcie/rcec.c
>> +++ b/drivers/pci/pcie/rcec.c
>> @@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
>>
>> walk_rcec(walk_rcec_helper, &rcec_data);
>> }
>> +EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
>
> Same thing as above?
>
>>
>> void pci_rcec_init(struct pci_dev *dev)
>> {
>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>> index 6b2c87d1b5b6..64aef69fb546 100644
>> --- a/include/linux/aer.h
>> +++ b/include/linux/aer.h
>> @@ -66,6 +66,7 @@ struct cxl_proto_err_work_data {
>>
>> #if defined(CONFIG_PCIEAER)
>> int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>> +void pci_aer_clear_fatal_status(struct pci_dev *dev);
>> int pcie_aer_is_native(struct pci_dev *dev);
>> void pci_aer_unmask_internal_errors(struct pci_dev *dev);
>> #else
>> @@ -73,6 +74,7 @@ static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>> {
>> return -EINVAL;
>> }
>> +static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>> static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
>> static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
>> #endif
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index bc3a7b6d0f94..b8e36bde346c 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -1825,6 +1825,9 @@ extern bool pcie_ports_native;
>>
>> int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
>> bool use_lt);
>> +void pcie_walk_rcec(struct pci_dev *rcec,
>> + int (*cb)(struct pci_dev *, void *),
>> + void *userdata);
>> #else
>> #define pcie_ports_disabled true
>> #define pcie_ports_native false
>> @@ -1835,8 +1838,14 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
>> {
>> return -EOPNOTSUPP;
>> }
>> +
>> +static inline void pcie_walk_rcec(struct pci_dev *rcec,
>> + int (*cb)(struct pci_dev *, void *),
>> + void *userdata) { }
>> #endif
>>
>> +void pcie_clear_device_status(struct pci_dev *dev);
>> +
>> #define PCIE_LINK_STATE_L0S (BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
>> #define PCIE_LINK_STATE_L1 BIT(2) /* L1 state */
>> #define PCIE_LINK_STATE_L1_1 BIT(3) /* ASPM L1.1 state */
>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 21/25] CXL/PCI: Introduce CXL Port protocol error handlers
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (19 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 20/25] PCI/AER: Dequeue forwarded CXL error Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-29 23:32 ` Dave Jiang
2025-10-03 20:12 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 22/25] CXL/PCI: Export and rename merge_result() to pci_ers_merge_result() Terry Bowman
` (3 subsequent siblings)
24 siblings, 2 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
Introduce CXL error handlers for CXL Port devices.
Add functions cxl_port_cor_error_detected() and cxl_port_error_detected().
These will serve as the handlers for all CXL Port devices. Introduce
cxl_get_ras_base() to provide the RAS base address needed by the handlers.
Update cxl_handle_proto_error() to call the CXL Port or CXL Endpoint
handler depending on which CXL device reports the error.
Implement cxl_get_ras_base() to return the cached RAS register address of a
CXL Root Port, CXL Downstream Port, or CXL Upstream Port.
Introduce get_pci_cxl_host_dev() to return the host responsible for
releasing the RAS mapped resources. CXL endpoints do not use a host to
manage its resources, allow for NULL in the case of an EP. Use reference
count increment on the host to prevent resource release. Make the caller
responsible for the reference decrement.
Update the AER driver's is_cxl_error() PCI type check because CXL Port
devices are now supported.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
Changes in v11->v12:
- Add call to cxl_pci_drv_bound() in cxl_handle_proto_error() and
pci_to_cxl_dev()
- Change cxl_error_detected() -> cxl_cor_error_detected()
- Remove NULL variable assignments
- Replace bus_find_device() with find_cxl_port_by_uport() for upstream
port searches.
Changes in v10->v11:
- None
---
drivers/cxl/core/core.h | 10 +++
drivers/cxl/core/port.c | 7 +-
drivers/cxl/core/ras.c | 159 ++++++++++++++++++++++++++++++++--
drivers/pci/pcie/aer_cxl_vh.c | 5 +-
4 files changed, 170 insertions(+), 11 deletions(-)
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 9ceff8acf844..3197a71bf7b8 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -156,6 +156,8 @@ pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
void pci_cor_error_detected(struct pci_dev *pdev);
void cxl_cor_error_detected(struct device *dev);
pci_ers_result_t cxl_error_detected(struct device *dev);
+void cxl_port_cor_error_detected(struct device *dev);
+pci_ers_result_t cxl_port_error_detected(struct device *dev);
#else
static inline int cxl_ras_init(void)
{
@@ -180,9 +182,17 @@ static inline pci_ers_result_t cxl_error_detected(struct device *dev)
{
return PCI_ERS_RESULT_NONE;
}
+static inline void cxl_port_cor_error_detected(struct device *dev) { }
+static inline pci_ers_result_t cxl_port_error_detected(struct device *dev)
+{
+ return PCI_ERS_RESULT_NONE;
+}
#endif // CONFIG_CXL_RAS
int cxl_gpf_port_setup(struct cxl_dport *dport);
+struct cxl_port *find_cxl_port(struct device *dport_dev,
+ struct cxl_dport **dport);
+struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev);
struct cxl_hdm;
int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 56fa4ac33e8b..f34a44abb2c9 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -1357,8 +1357,8 @@ static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)
return NULL;
}
-static struct cxl_port *find_cxl_port(struct device *dport_dev,
- struct cxl_dport **dport)
+struct cxl_port *find_cxl_port(struct device *dport_dev,
+ struct cxl_dport **dport)
{
struct cxl_find_port_ctx ctx = {
.dport_dev = dport_dev,
@@ -1561,7 +1561,7 @@ static int match_port_by_uport(struct device *dev, const void *data)
* Function takes a device reference on the port device. Caller should do a
* put_device() when done.
*/
-static struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
+struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
{
struct device *dev;
@@ -1570,6 +1570,7 @@ static struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
return to_cxl_port(dev);
return NULL;
}
+EXPORT_SYMBOL_NS_GPL(find_cxl_port_by_uport, "CXL");
static int update_decoder_targets(struct device *dev, void *data)
{
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 9acfe24ba3bb..7e8d63c32d72 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -250,6 +250,129 @@ static void cxl_dport_map_ras(struct cxl_dport *dport)
dev_dbg(dev, "Failed to map RAS capability.\n");
}
+static void __iomem *cxl_get_ras_base(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ switch (pci_pcie_type(pdev)) {
+ case PCI_EXP_TYPE_ROOT_PORT:
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ {
+ struct cxl_dport *dport;
+ struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
+
+ if (!dport || !dport->dport_dev) {
+ pci_err(pdev, "Failed to find the CXL device");
+ return NULL;
+ }
+
+ return dport->regs.ras;
+ }
+ case PCI_EXP_TYPE_UPSTREAM:
+ {
+ struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
+
+ if (!port) {
+ pci_err(pdev, "Failed to find the CXL device");
+ return NULL;
+ }
+
+ return port->uport_regs.ras;
+ }
+ }
+
+ dev_warn_once(dev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
+ return NULL;
+}
+
+static struct device *pci_to_cxl_dev(struct pci_dev *pdev)
+{
+ switch (pci_pcie_type(pdev)) {
+ case PCI_EXP_TYPE_ROOT_PORT:
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ {
+ struct cxl_dport *dport;
+ struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
+
+ if (!port) {
+ pci_err(pdev, "Failed to find the CXL device");
+ return NULL;
+ }
+
+ return dport->dport_dev;
+ }
+ case PCI_EXP_TYPE_UPSTREAM:
+ {
+ struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
+
+ if (!port) {
+ pci_err(pdev, "Failed to find the CXL device");
+ return NULL;
+ }
+
+ return port->uport_dev;
+ }
+ case PCI_EXP_TYPE_ENDPOINT:
+ {
+ struct cxl_dev_state *cxlds;
+
+ if (!cxl_pci_drv_bound(pdev))
+ return NULL;
+
+ cxlds = pci_get_drvdata(pdev);
+ return cxlds->dev;
+ }
+ }
+
+ pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
+ return NULL;
+}
+
+/*
+ * Return 'struct device *' responsible for freeing pdev's CXL resources.
+ * Caller is responsible for reference count decrementing the return
+ * 'struct device *'.
+ *
+ * dev: Find the host of this dev
+ */
+static struct device *get_cxl_host_dev(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ switch (pci_pcie_type(pdev)) {
+ case PCI_EXP_TYPE_ROOT_PORT:
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ {
+ struct cxl_dport *dport;
+ struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
+
+ if (!port) {
+ pci_err(pdev, "Failed to find the CXL device");
+ return NULL;
+ }
+
+ return &port->dev;
+ }
+ case PCI_EXP_TYPE_UPSTREAM:
+ {
+ struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
+
+ if (!port) {
+ pci_err(pdev, "Failed to find the CXL device");
+ return NULL;
+ }
+
+ return &port->dev;
+ }
+ /* Endpoint resources are managed by endpoint itself */
+ case PCI_EXP_TYPE_ENDPOINT:
+ return NULL;
+ }
+
+ dev_warn_once(dev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
+ return NULL;
+}
+
/**
* cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
* @dport: the cxl_dport that needs to be initialized
@@ -399,6 +522,22 @@ static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __io
return PCI_ERS_RESULT_PANIC;
}
+void cxl_port_cor_error_detected(struct device *dev)
+{
+ void __iomem *ras_base = cxl_get_ras_base(dev);
+
+ cxl_handle_cor_ras(dev, 0, ras_base);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_port_cor_error_detected, "CXL");
+
+pci_ers_result_t cxl_port_error_detected(struct device *dev)
+{
+ void __iomem *ras_base = cxl_get_ras_base(dev);
+
+ return cxl_handle_ras(dev, 0, ras_base);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_port_error_detected, "CXL");
+
void cxl_cor_error_detected(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@@ -469,9 +608,8 @@ EXPORT_SYMBOL_NS_GPL(pci_error_detected, "CXL");
static void cxl_handle_proto_error(struct cxl_proto_err_work_data *err_info)
{
struct pci_dev *pdev = err_info->pdev;
- struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
- struct cxl_memdev *cxlmd = cxlds->cxlmd;
- struct device *host_dev __free(put_device) = get_device(&cxlmd->dev);
+ struct device *dev = pci_to_cxl_dev(pdev);
+ struct device *host_dev __free(put_device) = get_cxl_host_dev(&pdev->dev);
if (err_info->severity == AER_CORRECTABLE) {
int aer = pdev->aer_cap;
@@ -483,13 +621,20 @@ static void cxl_handle_proto_error(struct cxl_proto_err_work_data *err_info)
aer + PCI_ERR_COR_STATUS,
0, PCI_ERR_COR_INTERNAL);
- if (!cxl_pci_drv_bound(pdev))
- return;
+ if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) {
+
+ if (!cxl_pci_drv_bound(pdev))
+ return;
+
+ cxl_cor_error_detected(dev);
+
+ } else {
+ cxl_port_cor_error_detected(dev);
+ }
- cxl_cor_error_detected(&cxlmd->dev);
pcie_clear_device_status(pdev);
} else {
- cxl_do_recovery(&cxlmd->dev);
+ cxl_do_recovery(dev);
}
}
diff --git a/drivers/pci/pcie/aer_cxl_vh.c b/drivers/pci/pcie/aer_cxl_vh.c
index 8c0979299446..dbd7cb5d1a0a 100644
--- a/drivers/pci/pcie/aer_cxl_vh.c
+++ b/drivers/pci/pcie/aer_cxl_vh.c
@@ -43,7 +43,10 @@ bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
if (!info || !info->is_cxl)
return false;
- if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT)
+ if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
+ (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) &&
+ (pci_pcie_type(pdev) != PCI_EXP_TYPE_UPSTREAM) &&
+ (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM))
return false;
return is_internal_error(info);
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 21/25] CXL/PCI: Introduce CXL Port protocol error handlers
2025-09-25 22:34 ` [PATCH v12 21/25] CXL/PCI: Introduce CXL Port protocol error handlers Terry Bowman
@ 2025-09-29 23:32 ` Dave Jiang
2025-10-03 20:12 ` Cheatham, Benjamin
1 sibling, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-29 23:32 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> Introduce CXL error handlers for CXL Port devices.
>
> Add functions cxl_port_cor_error_detected() and cxl_port_error_detected().
> These will serve as the handlers for all CXL Port devices. Introduce
> cxl_get_ras_base() to provide the RAS base address needed by the handlers.
>
> Update cxl_handle_proto_error() to call the CXL Port or CXL Endpoint
> handler depending on which CXL device reports the error.
>
> Implement cxl_get_ras_base() to return the cached RAS register address of a
> CXL Root Port, CXL Downstream Port, or CXL Upstream Port.
>
> Introduce get_pci_cxl_host_dev() to return the host responsible for
> releasing the RAS mapped resources. CXL endpoints do not use a host to
> manage its resources, allow for NULL in the case of an EP. Use reference
> count increment on the host to prevent resource release. Make the caller
> responsible for the reference decrement.
>
> Update the AER driver's is_cxl_error() PCI type check because CXL Port
> devices are now supported.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> ---
>
> Changes in v11->v12:
> - Add call to cxl_pci_drv_bound() in cxl_handle_proto_error() and
> pci_to_cxl_dev()
> - Change cxl_error_detected() -> cxl_cor_error_detected()
> - Remove NULL variable assignments
> - Replace bus_find_device() with find_cxl_port_by_uport() for upstream
> port searches.
>
> Changes in v10->v11:
> - None
> ---
> drivers/cxl/core/core.h | 10 +++
> drivers/cxl/core/port.c | 7 +-
> drivers/cxl/core/ras.c | 159 ++++++++++++++++++++++++++++++++--
> drivers/pci/pcie/aer_cxl_vh.c | 5 +-
> 4 files changed, 170 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
> index 9ceff8acf844..3197a71bf7b8 100644
> --- a/drivers/cxl/core/core.h
> +++ b/drivers/cxl/core/core.h
> @@ -156,6 +156,8 @@ pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
> void pci_cor_error_detected(struct pci_dev *pdev);
> void cxl_cor_error_detected(struct device *dev);
> pci_ers_result_t cxl_error_detected(struct device *dev);
> +void cxl_port_cor_error_detected(struct device *dev);
> +pci_ers_result_t cxl_port_error_detected(struct device *dev);
> #else
> static inline int cxl_ras_init(void)
> {
> @@ -180,9 +182,17 @@ static inline pci_ers_result_t cxl_error_detected(struct device *dev)
> {
> return PCI_ERS_RESULT_NONE;
> }
> +static inline void cxl_port_cor_error_detected(struct device *dev) { }
> +static inline pci_ers_result_t cxl_port_error_detected(struct device *dev)
> +{
> + return PCI_ERS_RESULT_NONE;
> +}
> #endif // CONFIG_CXL_RAS
>
> int cxl_gpf_port_setup(struct cxl_dport *dport);
> +struct cxl_port *find_cxl_port(struct device *dport_dev,
> + struct cxl_dport **dport);
> +struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev);
>
> struct cxl_hdm;
> int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index 56fa4ac33e8b..f34a44abb2c9 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -1357,8 +1357,8 @@ static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)
> return NULL;
> }
>
> -static struct cxl_port *find_cxl_port(struct device *dport_dev,
> - struct cxl_dport **dport)
> +struct cxl_port *find_cxl_port(struct device *dport_dev,
> + struct cxl_dport **dport)
> {
> struct cxl_find_port_ctx ctx = {
> .dport_dev = dport_dev,
> @@ -1561,7 +1561,7 @@ static int match_port_by_uport(struct device *dev, const void *data)
> * Function takes a device reference on the port device. Caller should do a
> * put_device() when done.
> */
> -static struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
> +struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
> {
> struct device *dev;
>
> @@ -1570,6 +1570,7 @@ static struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
> return to_cxl_port(dev);
> return NULL;
> }
> +EXPORT_SYMBOL_NS_GPL(find_cxl_port_by_uport, "CXL");
Why export this in this commit? Not seeing usage outside of core/ras.c.
>
> static int update_decoder_targets(struct device *dev, void *data)
> {
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 9acfe24ba3bb..7e8d63c32d72 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -250,6 +250,129 @@ static void cxl_dport_map_ras(struct cxl_dport *dport)
> dev_dbg(dev, "Failed to map RAS capability.\n");
> }
>
> +static void __iomem *cxl_get_ras_base(struct device *dev)
I think this can be a pci_dev for input
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> +
> + switch (pci_pcie_type(pdev)) {
> + case PCI_EXP_TYPE_ROOT_PORT:
> + case PCI_EXP_TYPE_DOWNSTREAM:
> + {
> + struct cxl_dport *dport;
> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
> +
> + if (!dport || !dport->dport_dev) {
Is it possible to have a 'cxl_dport' but not a dport->dport_dev?
> + pci_err(pdev, "Failed to find the CXL device");
> + return NULL;
> + }
> +
> + return dport->regs.ras;
> + }
> + case PCI_EXP_TYPE_UPSTREAM:
> + {
> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
> +
> + if (!port) {
> + pci_err(pdev, "Failed to find the CXL device");
> + return NULL;
> + }
> +
> + return port->uport_regs.ras;
> + }
> + }
> +
> + dev_warn_once(dev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
> + return NULL;
> +}
> +
> +static struct device *pci_to_cxl_dev(struct pci_dev *pdev)
I think this should return a pci_dev right?
Also, are you using this function to verify that it belongs to a valid CXL port hierarchy? Otherwise you are just returning &pdev->dev looks like?
It seems like you can rename pci_to_cxl_dev() to has_cxl_port(). And later on you can do:
struct pci_dev *pdev __free(pci_dev_put) = has_cxl_port(err_info->pdev) ? pci_dev_get(err_info->pdev) : NULL;
And then you can pass in pdev to all the calls after after checking to make sure pdev isn't NULL.
> +{
> + switch (pci_pcie_type(pdev)) {
> + case PCI_EXP_TYPE_ROOT_PORT:
> + case PCI_EXP_TYPE_DOWNSTREAM:
> + {
> + struct cxl_dport *dport;
> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
> +
> + if (!port) {
> + pci_err(pdev, "Failed to find the CXL device");
> + return NULL;
> + }
> +
> + return dport->dport_dev;
> + }
> + case PCI_EXP_TYPE_UPSTREAM:
> + {
> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
> +
> + if (!port) {
> + pci_err(pdev, "Failed to find the CXL device");
> + return NULL;
> + }
> +
> + return port->uport_dev;
> + }
> + case PCI_EXP_TYPE_ENDPOINT:
> + {
> + struct cxl_dev_state *cxlds;
> +
> + if (!cxl_pci_drv_bound(pdev))
> + return NULL;
> +
> + cxlds = pci_get_drvdata(pdev);
> + return cxlds->dev;
> + }
> + }
> +
> + pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
> + return NULL;
> +}
> +
> +/*
> + * Return 'struct device *' responsible for freeing pdev's CXL resources.
> + * Caller is responsible for reference count decrementing the return
> + * 'struct device *'.
> + *
> + * dev: Find the host of this dev
> + */
> +static struct device *get_cxl_host_dev(struct device *dev)
get_cxl_port_dev()?
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> +
> + switch (pci_pcie_type(pdev)) {
> + case PCI_EXP_TYPE_ROOT_PORT:
> + case PCI_EXP_TYPE_DOWNSTREAM:
> + {
> + struct cxl_dport *dport;
> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
> +
> + if (!port) {
> + pci_err(pdev, "Failed to find the CXL device");
> + return NULL;
> + }
> +
> + return &port->dev;
> + }
> + case PCI_EXP_TYPE_UPSTREAM:
> + {
> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
> +
> + if (!port) {
> + pci_err(pdev, "Failed to find the CXL device");
> + return NULL;
> + }
> +
> + return &port->dev;
> + }
> + /* Endpoint resources are managed by endpoint itself */
> + case PCI_EXP_TYPE_ENDPOINT:
> + return NULL;
> + }
> +
> + dev_warn_once(dev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
> + return NULL;
> +}
> +
> /**
> * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
> * @dport: the cxl_dport that needs to be initialized
> @@ -399,6 +522,22 @@ static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial, void __io
> return PCI_ERS_RESULT_PANIC;
> }
>
> +void cxl_port_cor_error_detected(struct device *dev)
pci_dev?
> +{
> + void __iomem *ras_base = cxl_get_ras_base(dev);
> +
> + cxl_handle_cor_ras(dev, 0, ras_base);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_port_cor_error_detected, "CXL");
> +
> +pci_ers_result_t cxl_port_error_detected(struct device *dev)
pci_dev?
> +{
> + void __iomem *ras_base = cxl_get_ras_base(dev);
> +
> + return cxl_handle_ras(dev, 0, ras_base);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_port_error_detected, "CXL");
> +
> void cxl_cor_error_detected(struct device *dev)
> {
> struct pci_dev *pdev = to_pci_dev(dev);
> @@ -469,9 +608,8 @@ EXPORT_SYMBOL_NS_GPL(pci_error_detected, "CXL");
> static void cxl_handle_proto_error(struct cxl_proto_err_work_data *err_info)
> {
> struct pci_dev *pdev = err_info->pdev;
> - struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> - struct cxl_memdev *cxlmd = cxlds->cxlmd;
> - struct device *host_dev __free(put_device) = get_device(&cxlmd->dev);
> + struct device *dev = pci_to_cxl_dev(pdev);
> + struct device *host_dev __free(put_device) = get_cxl_host_dev(&pdev->dev);
At this point, host_dev is not being used anywhere. Belongs in a different patch?
>
> if (err_info->severity == AER_CORRECTABLE) {
> int aer = pdev->aer_cap;
> @@ -483,13 +621,20 @@ static void cxl_handle_proto_error(struct cxl_proto_err_work_data *err_info)
> aer + PCI_ERR_COR_STATUS,
> 0, PCI_ERR_COR_INTERNAL);
>
> - if (!cxl_pci_drv_bound(pdev))
> - return;
> + if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) {
> +
> + if (!cxl_pci_drv_bound(pdev))
> + return;
> +
> + cxl_cor_error_detected(dev);
Using dev w/o checking if it's NULL. pci_to_cxl_dev() can return NULL.
DJ
> +
> + } else {
> + cxl_port_cor_error_detected(dev);
> + }
>
> - cxl_cor_error_detected(&cxlmd->dev);
> pcie_clear_device_status(pdev);
> } else {
> - cxl_do_recovery(&cxlmd->dev);
> + cxl_do_recovery(dev);
> }
> }
>
> diff --git a/drivers/pci/pcie/aer_cxl_vh.c b/drivers/pci/pcie/aer_cxl_vh.c
> index 8c0979299446..dbd7cb5d1a0a 100644
> --- a/drivers/pci/pcie/aer_cxl_vh.c
> +++ b/drivers/pci/pcie/aer_cxl_vh.c
> @@ -43,7 +43,10 @@ bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
> if (!info || !info->is_cxl)
> return false;
>
> - if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT)
> + if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
> + (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) &&
> + (pci_pcie_type(pdev) != PCI_EXP_TYPE_UPSTREAM) &&
> + (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM))
> return false;
>
> return is_internal_error(info);
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 21/25] CXL/PCI: Introduce CXL Port protocol error handlers
2025-09-25 22:34 ` [PATCH v12 21/25] CXL/PCI: Introduce CXL Port protocol error handlers Terry Bowman
2025-09-29 23:32 ` Dave Jiang
@ 2025-10-03 20:12 ` Cheatham, Benjamin
2025-10-06 21:28 ` Bowman, Terry
1 sibling, 1 reply; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:12 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> Introduce CXL error handlers for CXL Port devices.
>
> Add functions cxl_port_cor_error_detected() and cxl_port_error_detected().
> These will serve as the handlers for all CXL Port devices. Introduce
> cxl_get_ras_base() to provide the RAS base address needed by the handlers.
>
> Update cxl_handle_proto_error() to call the CXL Port or CXL Endpoint
> handler depending on which CXL device reports the error.
>
> Implement cxl_get_ras_base() to return the cached RAS register address of a
> CXL Root Port, CXL Downstream Port, or CXL Upstream Port.
>
> Introduce get_pci_cxl_host_dev() to return the host responsible for
> releasing the RAS mapped resources. CXL endpoints do not use a host to
> manage its resources, allow for NULL in the case of an EP. Use reference
> count increment on the host to prevent resource release. Make the caller
> responsible for the reference decrement.
>
> Update the AER driver's is_cxl_error() PCI type check because CXL Port
> devices are now supported.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> ---
>
> Changes in v11->v12:
> - Add call to cxl_pci_drv_bound() in cxl_handle_proto_error() and
> pci_to_cxl_dev()
> - Change cxl_error_detected() -> cxl_cor_error_detected()
> - Remove NULL variable assignments
> - Replace bus_find_device() with find_cxl_port_by_uport() for upstream
> port searches.
>
> Changes in v10->v11:
> - None
> ---
> drivers/cxl/core/core.h | 10 +++
> drivers/cxl/core/port.c | 7 +-
> drivers/cxl/core/ras.c | 159 ++++++++++++++++++++++++++++++++--
> drivers/pci/pcie/aer_cxl_vh.c | 5 +-
> 4 files changed, 170 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
> index 9ceff8acf844..3197a71bf7b8 100644
> --- a/drivers/cxl/core/core.h
> +++ b/drivers/cxl/core/core.h
> @@ -156,6 +156,8 @@ pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
> void pci_cor_error_detected(struct pci_dev *pdev);
> void cxl_cor_error_detected(struct device *dev);
> pci_ers_result_t cxl_error_detected(struct device *dev);
> +void cxl_port_cor_error_detected(struct device *dev);
> +pci_ers_result_t cxl_port_error_detected(struct device *dev);
> #else
> static inline int cxl_ras_init(void)
> {
> @@ -180,9 +182,17 @@ static inline pci_ers_result_t cxl_error_detected(struct device *dev)
> {
> return PCI_ERS_RESULT_NONE;
> }
> +static inline void cxl_port_cor_error_detected(struct device *dev) { }
> +static inline pci_ers_result_t cxl_port_error_detected(struct device *dev)
> +{
> + return PCI_ERS_RESULT_NONE;
Same question as endpoint error handler on if this should be a PCI_ERS_RESULT_PANIC instead.
> +}
> #endif // CONFIG_CXL_RAS
Wrong comment style.
>
> int cxl_gpf_port_setup(struct cxl_dport *dport);
> +struct cxl_port *find_cxl_port(struct device *dport_dev,
> + struct cxl_dport **dport);
> +struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev);
>
> struct cxl_hdm;
> int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index 56fa4ac33e8b..f34a44abb2c9 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -1357,8 +1357,8 @@ static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)
> return NULL;
> }
>
> -static struct cxl_port *find_cxl_port(struct device *dport_dev,
> - struct cxl_dport **dport)
> +struct cxl_port *find_cxl_port(struct device *dport_dev,
> + struct cxl_dport **dport)
> {
> struct cxl_find_port_ctx ctx = {
> .dport_dev = dport_dev,
> @@ -1561,7 +1561,7 @@ static int match_port_by_uport(struct device *dev, const void *data)
> * Function takes a device reference on the port device. Caller should do a
> * put_device() when done.
> */
> -static struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
> +struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
> {
> struct device *dev;
>
> @@ -1570,6 +1570,7 @@ static struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
> return to_cxl_port(dev);
> return NULL;
> }
> +EXPORT_SYMBOL_NS_GPL(find_cxl_port_by_uport, "CXL");
>
> static int update_decoder_targets(struct device *dev, void *data)
> {
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 9acfe24ba3bb..7e8d63c32d72 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -250,6 +250,129 @@ static void cxl_dport_map_ras(struct cxl_dport *dport)
> dev_dbg(dev, "Failed to map RAS capability.\n");
> }
>
> +static void __iomem *cxl_get_ras_base(struct device *dev)
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> +
> + switch (pci_pcie_type(pdev)) {
> + case PCI_EXP_TYPE_ROOT_PORT:
> + case PCI_EXP_TYPE_DOWNSTREAM:
> + {
> + struct cxl_dport *dport;
> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
> +
> + if (!dport || !dport->dport_dev) {
> + pci_err(pdev, "Failed to find the CXL device");
> + return NULL;
> + }
> +
> + return dport->regs.ras;
> + }
> + case PCI_EXP_TYPE_UPSTREAM:
> + {
> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
> +
> + if (!port) {
> + pci_err(pdev, "Failed to find the CXL device");
> + return NULL;
> + }
> +
> + return port->uport_regs.ras;
> + }
> + }
> +
> + dev_warn_once(dev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
> + return NULL;
> +}
> +
> +static struct device *pci_to_cxl_dev(struct pci_dev *pdev)
> +{
> + switch (pci_pcie_type(pdev)) {
> + case PCI_EXP_TYPE_ROOT_PORT:
> + case PCI_EXP_TYPE_DOWNSTREAM:
> + {
> + struct cxl_dport *dport;
> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
> +
> + if (!port) {
> + pci_err(pdev, "Failed to find the CXL device");
> + return NULL;
> + }
> +
> + return dport->dport_dev;
> + }
> + case PCI_EXP_TYPE_UPSTREAM:
> + {
> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
> +
> + if (!port) {
> + pci_err(pdev, "Failed to find the CXL device");
> + return NULL;
> + }
> +
> + return port->uport_dev;
> + }
> + case PCI_EXP_TYPE_ENDPOINT:
> + {
> + struct cxl_dev_state *cxlds;
> +
> + if (!cxl_pci_drv_bound(pdev))
> + return NULL;
> +
> + cxlds = pci_get_drvdata(pdev);
> + return cxlds->dev;
> + }
> + }
> +
> + pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
> + return NULL;
> +}
> +
> +/*
> + * Return 'struct device *' responsible for freeing pdev's CXL resources.
> + * Caller is responsible for reference count decrementing the return
> + * 'struct device *'.
> + *
> + * dev: Find the host of this dev
> + */
> +static struct device *get_cxl_host_dev(struct device *dev)
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> +
> + switch (pci_pcie_type(pdev)) {
> + case PCI_EXP_TYPE_ROOT_PORT:
> + case PCI_EXP_TYPE_DOWNSTREAM:
> + {
> + struct cxl_dport *dport;
> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
> +
> + if (!port) {
> + pci_err(pdev, "Failed to find the CXL device");
> + return NULL;
> + }
> +
> + return &port->dev;
I may just be tired, but won't the __free() action get called here unless you use no_free_ptr()?
You do the same thing with cxl_get_ras_base() and pci_to_cxl_dev() above, though I think it's the
intended behavior for the latter function.
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 21/25] CXL/PCI: Introduce CXL Port protocol error handlers
2025-10-03 20:12 ` Cheatham, Benjamin
@ 2025-10-06 21:28 ` Bowman, Terry
0 siblings, 0 replies; 92+ messages in thread
From: Bowman, Terry @ 2025-10-06 21:28 UTC (permalink / raw)
To: Cheatham, Benjamin
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 10/3/2025 3:12 PM, Cheatham, Benjamin wrote:
> On 9/25/2025 5:34 PM, Terry Bowman wrote:
>> Introduce CXL error handlers for CXL Port devices.
>>
>> Add functions cxl_port_cor_error_detected() and cxl_port_error_detected().
>> These will serve as the handlers for all CXL Port devices. Introduce
>> cxl_get_ras_base() to provide the RAS base address needed by the handlers.
>>
>> Update cxl_handle_proto_error() to call the CXL Port or CXL Endpoint
>> handler depending on which CXL device reports the error.
>>
>> Implement cxl_get_ras_base() to return the cached RAS register address of a
>> CXL Root Port, CXL Downstream Port, or CXL Upstream Port.
>>
>> Introduce get_pci_cxl_host_dev() to return the host responsible for
>> releasing the RAS mapped resources. CXL endpoints do not use a host to
>> manage its resources, allow for NULL in the case of an EP. Use reference
>> count increment on the host to prevent resource release. Make the caller
>> responsible for the reference decrement.
>>
>> Update the AER driver's is_cxl_error() PCI type check because CXL Port
>> devices are now supported.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>>
>> ---
>>
>> Changes in v11->v12:
>> - Add call to cxl_pci_drv_bound() in cxl_handle_proto_error() and
>> pci_to_cxl_dev()
>> - Change cxl_error_detected() -> cxl_cor_error_detected()
>> - Remove NULL variable assignments
>> - Replace bus_find_device() with find_cxl_port_by_uport() for upstream
>> port searches.
>>
>> Changes in v10->v11:
>> - None
>> ---
>> drivers/cxl/core/core.h | 10 +++
>> drivers/cxl/core/port.c | 7 +-
>> drivers/cxl/core/ras.c | 159 ++++++++++++++++++++++++++++++++--
>> drivers/pci/pcie/aer_cxl_vh.c | 5 +-
>> 4 files changed, 170 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
>> index 9ceff8acf844..3197a71bf7b8 100644
>> --- a/drivers/cxl/core/core.h
>> +++ b/drivers/cxl/core/core.h
>> @@ -156,6 +156,8 @@ pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
>> void pci_cor_error_detected(struct pci_dev *pdev);
>> void cxl_cor_error_detected(struct device *dev);
>> pci_ers_result_t cxl_error_detected(struct device *dev);
>> +void cxl_port_cor_error_detected(struct device *dev);
>> +pci_ers_result_t cxl_port_error_detected(struct device *dev);
>> #else
>> static inline int cxl_ras_init(void)
>> {
>> @@ -180,9 +182,17 @@ static inline pci_ers_result_t cxl_error_detected(struct device *dev)
>> {
>> return PCI_ERS_RESULT_NONE;
>> }
>> +static inline void cxl_port_cor_error_detected(struct device *dev) { }
>> +static inline pci_ers_result_t cxl_port_error_detected(struct device *dev)
>> +{
>> + return PCI_ERS_RESULT_NONE;
> Same question as endpoint error handler on if this should be a PCI_ERS_RESULT_PANIC instead.
PCI_ERS_RESULT_NONE is correct. If CONFIG_CXL_RAS is disabled we don't want CXL RAS logic
running including the handling.
>> +}
>> #endif // CONFIG_CXL_RAS
> Wrong comment style.
Ok
>>
>> int cxl_gpf_port_setup(struct cxl_dport *dport);
>> +struct cxl_port *find_cxl_port(struct device *dport_dev,
>> + struct cxl_dport **dport);
>> +struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev);
>>
>> struct cxl_hdm;
>> int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>> index 56fa4ac33e8b..f34a44abb2c9 100644
>> --- a/drivers/cxl/core/port.c
>> +++ b/drivers/cxl/core/port.c
>> @@ -1357,8 +1357,8 @@ static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)
>> return NULL;
>> }
>>
>> -static struct cxl_port *find_cxl_port(struct device *dport_dev,
>> - struct cxl_dport **dport)
>> +struct cxl_port *find_cxl_port(struct device *dport_dev,
>> + struct cxl_dport **dport)
>> {
>> struct cxl_find_port_ctx ctx = {
>> .dport_dev = dport_dev,
>> @@ -1561,7 +1561,7 @@ static int match_port_by_uport(struct device *dev, const void *data)
>> * Function takes a device reference on the port device. Caller should do a
>> * put_device() when done.
>> */
>> -static struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
>> +struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
>> {
>> struct device *dev;
>>
>> @@ -1570,6 +1570,7 @@ static struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
>> return to_cxl_port(dev);
>> return NULL;
>> }
>> +EXPORT_SYMBOL_NS_GPL(find_cxl_port_by_uport, "CXL");
>>
>> static int update_decoder_targets(struct device *dev, void *data)
>> {
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 9acfe24ba3bb..7e8d63c32d72 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -250,6 +250,129 @@ static void cxl_dport_map_ras(struct cxl_dport *dport)
>> dev_dbg(dev, "Failed to map RAS capability.\n");
>> }
>>
>> +static void __iomem *cxl_get_ras_base(struct device *dev)
>> +{
>> + struct pci_dev *pdev = to_pci_dev(dev);
>> +
>> + switch (pci_pcie_type(pdev)) {
>> + case PCI_EXP_TYPE_ROOT_PORT:
>> + case PCI_EXP_TYPE_DOWNSTREAM:
>> + {
>> + struct cxl_dport *dport;
>> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
>> +
>> + if (!dport || !dport->dport_dev) {
>> + pci_err(pdev, "Failed to find the CXL device");
>> + return NULL;
>> + }
>> +
>> + return dport->regs.ras;
>> + }
>> + case PCI_EXP_TYPE_UPSTREAM:
>> + {
>> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
>> +
>> + if (!port) {
>> + pci_err(pdev, "Failed to find the CXL device");
>> + return NULL;
>> + }
>> +
>> + return port->uport_regs.ras;
>> + }
>> + }
>> +
>> + dev_warn_once(dev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
>> + return NULL;
>> +}
>> +
>> +static struct device *pci_to_cxl_dev(struct pci_dev *pdev)
>> +{
>> + switch (pci_pcie_type(pdev)) {
>> + case PCI_EXP_TYPE_ROOT_PORT:
>> + case PCI_EXP_TYPE_DOWNSTREAM:
>> + {
>> + struct cxl_dport *dport;
>> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
>> +
>> + if (!port) {
>> + pci_err(pdev, "Failed to find the CXL device");
>> + return NULL;
>> + }
>> +
>> + return dport->dport_dev;
>> + }
>> + case PCI_EXP_TYPE_UPSTREAM:
>> + {
>> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
>> +
>> + if (!port) {
>> + pci_err(pdev, "Failed to find the CXL device");
>> + return NULL;
>> + }
>> +
>> + return port->uport_dev;
>> + }
>> + case PCI_EXP_TYPE_ENDPOINT:
>> + {
>> + struct cxl_dev_state *cxlds;
>> +
>> + if (!cxl_pci_drv_bound(pdev))
>> + return NULL;
>> +
>> + cxlds = pci_get_drvdata(pdev);
>> + return cxlds->dev;
>> + }
>> + }
>> +
>> + pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
>> + return NULL;
>> +}
>> +
>> +/*
>> + * Return 'struct device *' responsible for freeing pdev's CXL resources.
>> + * Caller is responsible for reference count decrementing the return
>> + * 'struct device *'.
>> + *
>> + * dev: Find the host of this dev
>> + */
>> +static struct device *get_cxl_host_dev(struct device *dev)
>> +{
>> + struct pci_dev *pdev = to_pci_dev(dev);
>> +
>> + switch (pci_pcie_type(pdev)) {
>> + case PCI_EXP_TYPE_ROOT_PORT:
>> + case PCI_EXP_TYPE_DOWNSTREAM:
>> + {
>> + struct cxl_dport *dport;
>> + struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
>> +
>> + if (!port) {
>> + pci_err(pdev, "Failed to find the CXL device");
>> + return NULL;
>> + }
>> +
>> + return &port->dev;
> I may just be tired, but won't the __free() action get called here unless you use no_free_ptr()?
> You do the same thing with cxl_get_ras_base() and pci_to_cxl_dev() above, though I think it's the
> intended behavior for the latter function.
This needs updating to not use __free. Thanks.
Terry
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 22/25] CXL/PCI: Export and rename merge_result() to pci_ers_merge_result()
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (20 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 21/25] CXL/PCI: Introduce CXL Port protocol error handlers Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-26 15:01 ` kernel test robot
2025-09-26 18:10 ` kernel test robot
2025-09-25 22:34 ` [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery Terry Bowman
` (2 subsequent siblings)
24 siblings, 2 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
CXL uncorrectable errors (UCE) will soon be handled separately from the PCI
AER handling. The merge_result() function can be made common to use in both
handling paths.
Rename the PCI subsystem's merge_result() to be pci_ers_merge_result().
Export pci_ers_merge_result() to make available for the CXL and other
drivers to use.
Update pci_ers_merge_result() to support recently introduced PCI_ERS_RESULT_PANIC
result.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
Changes in v11->v12:
- Remove static inline pci_ers_merge_result() definition for !CONFIG_PCIEAER.
Is not needed. (Lukas)
Changes in v10->v11:
- New patch
- pci_ers_merge_result() - Change export to non-namespace and rename
to be pci_ers_merge_result()
- Move pci_ers_merge_result() definition to pci.h. Needs pci_ers_result
---
drivers/pci/pcie/err.c | 14 +++++++++-----
include/linux/pci.h | 2 ++
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c
index de6381c690f5..368bad0cb90e 100644
--- a/drivers/pci/pcie/err.c
+++ b/drivers/pci/pcie/err.c
@@ -21,9 +21,12 @@
#include "portdrv.h"
#include "../pci.h"
-static pci_ers_result_t merge_result(enum pci_ers_result orig,
- enum pci_ers_result new)
+pci_ers_result_t pci_ers_merge_result(enum pci_ers_result orig,
+ enum pci_ers_result new)
{
+ if (new == PCI_ERS_RESULT_PANIC)
+ return PCI_ERS_RESULT_PANIC;
+
if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
return PCI_ERS_RESULT_NO_AER_DRIVER;
@@ -45,6 +48,7 @@ static pci_ers_result_t merge_result(enum pci_ers_result orig,
return orig;
}
+EXPORT_SYMBOL(pci_ers_merge_result);
static int report_error_detected(struct pci_dev *dev,
pci_channel_state_t state,
@@ -81,7 +85,7 @@ static int report_error_detected(struct pci_dev *dev,
vote = err_handler->error_detected(dev, state);
}
pci_uevent_ers(dev, vote);
- *result = merge_result(*result, vote);
+ *result = pci_ers_merge_result(*result, vote);
device_unlock(&dev->dev);
return 0;
}
@@ -121,7 +125,7 @@ static int report_mmio_enabled(struct pci_dev *dev, void *data)
err_handler = pdrv->err_handler;
vote = err_handler->mmio_enabled(dev);
- *result = merge_result(*result, vote);
+ *result = pci_ers_merge_result(*result, vote);
out:
device_unlock(&dev->dev);
return 0;
@@ -140,7 +144,7 @@ static int report_slot_reset(struct pci_dev *dev, void *data)
err_handler = pdrv->err_handler;
vote = err_handler->slot_reset(dev);
- *result = merge_result(*result, vote);
+ *result = pci_ers_merge_result(*result, vote);
out:
device_unlock(&dev->dev);
return 0;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index b8e36bde346c..c7e8c9c5fda8 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1894,6 +1894,8 @@ static inline void pci_hp_unignore_link_change(struct pci_dev *pdev) { }
#ifdef CONFIG_PCIEAER
bool pci_aer_available(void);
+pci_ers_result_t pci_ers_merge_result(enum pci_ers_result orig,
+ enum pci_ers_result new);
#else
static inline bool pci_aer_available(void) { return false; }
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 22/25] CXL/PCI: Export and rename merge_result() to pci_ers_merge_result()
2025-09-25 22:34 ` [PATCH v12 22/25] CXL/PCI: Export and rename merge_result() to pci_ers_merge_result() Terry Bowman
@ 2025-09-26 15:01 ` kernel test robot
2025-09-26 18:10 ` kernel test robot
1 sibling, 0 replies; 92+ messages in thread
From: kernel test robot @ 2025-09-26 15:01 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: llvm, oe-kbuild-all, linux-kernel, linux-pci, terry.bowman
Hi Terry,
kernel test robot noticed the following build errors:
[auto build test ERROR on 46037455cbb748c5e85071c95f2244e81986eb58]
url: https://github.com/intel-lab-lkp/linux/commits/Terry-Bowman/cxl-pci-Remove-unnecessary-CXL-Endpoint-handling-helper-functions/20250926-064816
base: 46037455cbb748c5e85071c95f2244e81986eb58
patch link: https://lore.kernel.org/r/20250925223440.3539069-23-terry.bowman%40amd.com
patch subject: [PATCH v12 22/25] CXL/PCI: Export and rename merge_result() to pci_ers_merge_result()
config: powerpc64-randconfig-002-20250926 (https://download.01.org/0day-ci/archive/20250926/202509262230.gXBVTVxW-lkp@intel.com/config)
compiler: clang version 16.0.6 (https://github.com/llvm/llvm-project 7cbf1a2591520c2491aa35339f227775f4d3adf6)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250926/202509262230.gXBVTVxW-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/202509262230.gXBVTVxW-lkp@intel.com/
All errors (new ones prefixed by >>):
>> arch/powerpc/kernel/eeh_driver.c:68:28: error: static declaration of 'pci_ers_merge_result' follows non-static declaration
static enum pci_ers_result pci_ers_merge_result(enum pci_ers_result old,
^
include/linux/pci.h:1897:18: note: previous declaration is here
pci_ers_result_t pci_ers_merge_result(enum pci_ers_result orig,
^
1 error generated.
vim +/pci_ers_merge_result +68 arch/powerpc/kernel/eeh_driver.c
20b344971433da Sam Bobroff 2018-05-25 67
30424e386a30d1 Sam Bobroff 2018-05-25 @68 static enum pci_ers_result pci_ers_merge_result(enum pci_ers_result old,
30424e386a30d1 Sam Bobroff 2018-05-25 69 enum pci_ers_result new)
30424e386a30d1 Sam Bobroff 2018-05-25 70 {
30424e386a30d1 Sam Bobroff 2018-05-25 71 if (eeh_result_priority(new) > eeh_result_priority(old))
30424e386a30d1 Sam Bobroff 2018-05-25 72 return new;
30424e386a30d1 Sam Bobroff 2018-05-25 73 return old;
30424e386a30d1 Sam Bobroff 2018-05-25 74 }
30424e386a30d1 Sam Bobroff 2018-05-25 75
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 22/25] CXL/PCI: Export and rename merge_result() to pci_ers_merge_result()
2025-09-25 22:34 ` [PATCH v12 22/25] CXL/PCI: Export and rename merge_result() to pci_ers_merge_result() Terry Bowman
2025-09-26 15:01 ` kernel test robot
@ 2025-09-26 18:10 ` kernel test robot
1 sibling, 0 replies; 92+ messages in thread
From: kernel test robot @ 2025-09-26 18:10 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: oe-kbuild-all, linux-kernel, linux-pci, terry.bowman
Hi Terry,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 46037455cbb748c5e85071c95f2244e81986eb58]
url: https://github.com/intel-lab-lkp/linux/commits/Terry-Bowman/cxl-pci-Remove-unnecessary-CXL-Endpoint-handling-helper-functions/20250926-064816
base: 46037455cbb748c5e85071c95f2244e81986eb58
patch link: https://lore.kernel.org/r/20250925223440.3539069-23-terry.bowman%40amd.com
patch subject: [PATCH v12 22/25] CXL/PCI: Export and rename merge_result() to pci_ers_merge_result()
config: powerpc-allmodconfig (https://download.01.org/0day-ci/archive/20250927/202509270131.UIdODBaV-lkp@intel.com/config)
compiler: powerpc64-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250927/202509270131.UIdODBaV-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/202509270131.UIdODBaV-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> arch/powerpc/kernel/eeh_driver.c:68:28: warning: conflicting types for 'pci_ers_merge_result' due to enum/integer mismatch; have 'enum pci_ers_result(enum pci_ers_result, enum pci_ers_result)' [-Wenum-int-mismatch]
68 | static enum pci_ers_result pci_ers_merge_result(enum pci_ers_result old,
| ^~~~~~~~~~~~~~~~~~~~
arch/powerpc/kernel/eeh_driver.c:68:28: error: static declaration of 'pci_ers_merge_result' follows non-static declaration
In file included from arch/powerpc/kernel/eeh_driver.c:13:
include/linux/pci.h:1897:18: note: previous declaration of 'pci_ers_merge_result' with type 'pci_ers_result_t(enum pci_ers_result, enum pci_ers_result)' {aka 'unsigned int(enum pci_ers_result, enum pci_ers_result)'}
1897 | pci_ers_result_t pci_ers_merge_result(enum pci_ers_result orig,
| ^~~~~~~~~~~~~~~~~~~~
vim +68 arch/powerpc/kernel/eeh_driver.c
20b344971433da Sam Bobroff 2018-05-25 67
30424e386a30d1 Sam Bobroff 2018-05-25 @68 static enum pci_ers_result pci_ers_merge_result(enum pci_ers_result old,
30424e386a30d1 Sam Bobroff 2018-05-25 69 enum pci_ers_result new)
30424e386a30d1 Sam Bobroff 2018-05-25 70 {
30424e386a30d1 Sam Bobroff 2018-05-25 71 if (eeh_result_priority(new) > eeh_result_priority(old))
30424e386a30d1 Sam Bobroff 2018-05-25 72 return new;
30424e386a30d1 Sam Bobroff 2018-05-25 73 return old;
30424e386a30d1 Sam Bobroff 2018-05-25 74 }
30424e386a30d1 Sam Bobroff 2018-05-25 75
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (21 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 22/25] CXL/PCI: Export and rename merge_result() to pci_ers_merge_result() Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-30 0:26 ` Dave Jiang
2025-10-03 20:12 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 24/25] CXL/PCI: Enable CXL protocol errors during CXL Port probe Terry Bowman
2025-09-25 22:34 ` [PATCH v12 25/25] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup Terry Bowman
24 siblings, 2 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
Populate the cxl_do_recovery() function with uncorrectable protocol error (UCE)
handling. Follow similar design as found in PCIe error driver,
pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
as fatal with a kernel panic. This is to prevent corruption on CXL memory.
Introduce cxl_walk_port(). Make this analogous to pci_walk_bridge() but walking
CXL ports instead. This will iterate through the CXL topology from the
erroring device through the downstream CXL Ports and Endpoints.
Export pci_aer_clear_fatal_status() for CXL to use if a UCE is not found.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
Changes in v11->v12:
- Cleaned up port discovery in cxl_do_recovery() (Dave)
- Added PCI_EXP_TYPE_RC_END to type check in cxl_report_error_detected()
Changes in v10->v11:
- pci_ers_merge_results() - Move to earlier patch
---
drivers/cxl/core/ras.c | 111 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 111 insertions(+)
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 7e8d63c32d72..45f92defca64 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -443,8 +443,119 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
}
EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
+static int cxl_report_error_detected(struct device *dev, void *data)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ pci_ers_result_t vote, *result = data;
+
+ guard(device)(dev);
+
+ if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
+ (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
+ if (!cxl_pci_drv_bound(pdev))
+ return 0;
+
+ vote = cxl_error_detected(dev);
+ } else {
+ vote = cxl_port_error_detected(dev);
+ }
+
+ *result = pci_ers_merge_result(*result, vote);
+
+ return 0;
+}
+
+static int match_port_by_parent_dport(struct device *dev, const void *dport_dev)
+{
+ struct cxl_port *port;
+
+ if (!is_cxl_port(dev))
+ return 0;
+
+ port = to_cxl_port(dev);
+
+ return port->parent_dport->dport_dev == dport_dev;
+}
+
+static void cxl_walk_port(struct device *port_dev,
+ int (*cb)(struct device *, void *),
+ void *userdata)
+{
+ struct cxl_dport *dport = NULL;
+ struct cxl_port *port;
+ unsigned long index;
+
+ if (!port_dev)
+ return;
+
+ port = to_cxl_port(port_dev);
+ if (port->uport_dev && dev_is_pci(port->uport_dev))
+ cb(port->uport_dev, userdata);
+
+ xa_for_each(&port->dports, index, dport)
+ {
+ struct device *child_port_dev __free(put_device) =
+ bus_find_device(&cxl_bus_type, &port->dev, dport->dport_dev,
+ match_port_by_parent_dport);
+
+ cb(dport->dport_dev, userdata);
+
+ cxl_walk_port(child_port_dev, cxl_report_error_detected, userdata);
+ }
+
+ if (is_cxl_endpoint(port))
+ cb(port->uport_dev->parent, userdata);
+}
+
static void cxl_do_recovery(struct device *dev)
{
+ pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct cxl_port *port = NULL;
+
+ if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
+ (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM)) {
+ struct cxl_dport *dport;
+ struct cxl_port *rp_port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
+
+ port = rp_port;
+
+ } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_UPSTREAM) {
+ struct cxl_port *us_port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
+
+ port = us_port;
+
+ } else if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
+ (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
+ struct cxl_dev_state *cxlds;
+
+ if (!cxl_pci_drv_bound(pdev))
+ return;
+
+ cxlds = pci_get_drvdata(pdev);
+ port = cxlds->cxlmd->endpoint;
+ }
+
+ if (!port) {
+ dev_err(dev, "Failed to find the CXL device\n");
+ return;
+ }
+
+ cxl_walk_port(&port->dev, cxl_report_error_detected, &status);
+ if (status == PCI_ERS_RESULT_PANIC)
+ panic("CXL cachemem error.");
+
+ /*
+ * If we have native control of AER, clear error status in the device
+ * that detected the error. If the platform retained control of AER,
+ * it is responsible for clearing this status. In that case, the
+ * signaling device may not even be visible to the OS.
+ */
+ if (cxl_error_is_native(pdev)) {
+ pcie_clear_device_status(pdev);
+ pci_aer_clear_nonfatal_status(pdev);
+ pci_aer_clear_fatal_status(pdev);
+ }
}
static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
2025-09-25 22:34 ` [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery Terry Bowman
@ 2025-09-30 0:26 ` Dave Jiang
2025-09-30 14:38 ` Bowman, Terry
2025-10-03 20:12 ` Cheatham, Benjamin
1 sibling, 1 reply; 92+ messages in thread
From: Dave Jiang @ 2025-09-30 0:26 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> Populate the cxl_do_recovery() function with uncorrectable protocol error (UCE)
> handling. Follow similar design as found in PCIe error driver,
> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>
> Introduce cxl_walk_port(). Make this analogous to pci_walk_bridge() but walking
> CXL ports instead. This will iterate through the CXL topology from the
> erroring device through the downstream CXL Ports and Endpoints.
>
> Export pci_aer_clear_fatal_status() for CXL to use if a UCE is not found.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>
> ---
>
> Changes in v11->v12:
> - Cleaned up port discovery in cxl_do_recovery() (Dave)
> - Added PCI_EXP_TYPE_RC_END to type check in cxl_report_error_detected()
>
> Changes in v10->v11:
> - pci_ers_merge_results() - Move to earlier patch
> ---
> drivers/cxl/core/ras.c | 111 +++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 111 insertions(+)
>
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 7e8d63c32d72..45f92defca64 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -443,8 +443,119 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
> }
> EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>
> +static int cxl_report_error_detected(struct device *dev, void *data)
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> + pci_ers_result_t vote, *result = data;
> +
> + guard(device)(dev);
> +
> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
> + if (!cxl_pci_drv_bound(pdev))
> + return 0;
> +
> + vote = cxl_error_detected(dev);
> + } else {
> + vote = cxl_port_error_detected(dev);
> + }
> +
> + *result = pci_ers_merge_result(*result, vote);
> +
> + return 0;
> +}
> +
> +static int match_port_by_parent_dport(struct device *dev, const void *dport_dev)
> +{
> + struct cxl_port *port;
> +
> + if (!is_cxl_port(dev))
> + return 0;
> +
> + port = to_cxl_port(dev);
> +
> + return port->parent_dport->dport_dev == dport_dev;
> +}
> +
> +static void cxl_walk_port(struct device *port_dev,
> + int (*cb)(struct device *, void *),
> + void *userdata)
> +{
> + struct cxl_dport *dport = NULL;
> + struct cxl_port *port;
> + unsigned long index;
> +
> + if (!port_dev)
> + return;
> +
> + port = to_cxl_port(port_dev);
> + if (port->uport_dev && dev_is_pci(port->uport_dev))
> + cb(port->uport_dev, userdata);
Could use some comments on what is being walked. Also an explanation of what is happening here would be good.
If this is an endpoint port, this would be the PCI endpoint device.
If it's a switch port, then this is the upstream port.
If it's a root port, this is skipped.
> +
> + xa_for_each(&port->dports, index, dport)
> + {
> + struct device *child_port_dev __free(put_device) =
> + bus_find_device(&cxl_bus_type, &port->dev, dport->dport_dev,
> + match_port_by_parent_dport);
> +
> + cb(dport->dport_dev, userdata);
This is going through all the downstream ports
> +
> + cxl_walk_port(child_port_dev, cxl_report_error_detected, userdata);
> + }
> +
> + if (is_cxl_endpoint(port))
> + cb(port->uport_dev->parent, userdata);
And this is the downstream parent port of the endpoint device
Why not move this before the xa_for_each() and return early? endpoint ports don't have dports, no need to even try to run that block above.
So in the current implementation,
1. Endpoint. It checks the device, and then it checks the downstream parent port for errors. Is checking the parent dport necessary?
2. Switch. It checks the upstream port, then it checks all the downstream ports for errors.
3. Root port. It checks all the downstream ports for errors.
Is this the correct understanding of what this function does?
> +}
> +
> static void cxl_do_recovery(struct device *dev)
> {
> + pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
> + struct pci_dev *pdev = to_pci_dev(dev);
> + struct cxl_port *port = NULL;
> +
> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM)) {
> + struct cxl_dport *dport;
> + struct cxl_port *rp_port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
> +
> + port = rp_port;
> +
> + } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_UPSTREAM) {
> + struct cxl_port *us_port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
> +
> + port = us_port;
> +
> + } else if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
> + struct cxl_dev_state *cxlds;
> +
> + if (!cxl_pci_drv_bound(pdev))
> + return;
Need to have the pci dev lock before checking driver bound.
DJ
> +
> + cxlds = pci_get_drvdata(pdev);
> + port = cxlds->cxlmd->endpoint;
> + }
> +
> + if (!port) {
> + dev_err(dev, "Failed to find the CXL device\n");
> + return;
> + }
> +
> + cxl_walk_port(&port->dev, cxl_report_error_detected, &status);
> + if (status == PCI_ERS_RESULT_PANIC)
> + panic("CXL cachemem error.");
> +
> + /*
> + * If we have native control of AER, clear error status in the device
> + * that detected the error. If the platform retained control of AER,
> + * it is responsible for clearing this status. In that case, the
> + * signaling device may not even be visible to the OS.
> + */
> + if (cxl_error_is_native(pdev)) {
> + pcie_clear_device_status(pdev);
> + pci_aer_clear_nonfatal_status(pdev);
> + pci_aer_clear_fatal_status(pdev);
> + }
> }
>
> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
2025-09-30 0:26 ` Dave Jiang
@ 2025-09-30 14:38 ` Bowman, Terry
2025-09-30 16:13 ` Dave Jiang
0 siblings, 1 reply; 92+ messages in thread
From: Bowman, Terry @ 2025-09-30 14:38 UTC (permalink / raw)
To: Dave Jiang, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/29/2025 7:26 PM, Dave Jiang wrote:
>
> On 9/25/25 3:34 PM, Terry Bowman wrote:
>> Populate the cxl_do_recovery() function with uncorrectable protocol error (UCE)
>> handling. Follow similar design as found in PCIe error driver,
>> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
>> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>>
>> Introduce cxl_walk_port(). Make this analogous to pci_walk_bridge() but walking
>> CXL ports instead. This will iterate through the CXL topology from the
>> erroring device through the downstream CXL Ports and Endpoints.
>>
>> Export pci_aer_clear_fatal_status() for CXL to use if a UCE is not found.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>
>> ---
>>
>> Changes in v11->v12:
>> - Cleaned up port discovery in cxl_do_recovery() (Dave)
>> - Added PCI_EXP_TYPE_RC_END to type check in cxl_report_error_detected()
>>
>> Changes in v10->v11:
>> - pci_ers_merge_results() - Move to earlier patch
>> ---
>> drivers/cxl/core/ras.c | 111 +++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 111 insertions(+)
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 7e8d63c32d72..45f92defca64 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -443,8 +443,119 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
>> }
>> EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>>
>> +static int cxl_report_error_detected(struct device *dev, void *data)
>> +{
>> + struct pci_dev *pdev = to_pci_dev(dev);
>> + pci_ers_result_t vote, *result = data;
>> +
>> + guard(device)(dev);
>> +
>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
>> + if (!cxl_pci_drv_bound(pdev))
>> + return 0;
>> +
>> + vote = cxl_error_detected(dev);
>> + } else {
>> + vote = cxl_port_error_detected(dev);
>> + }
>> +
>> + *result = pci_ers_merge_result(*result, vote);
>> +
>> + return 0;
>> +}
>> +
>> +static int match_port_by_parent_dport(struct device *dev, const void *dport_dev)
>> +{
>> + struct cxl_port *port;
>> +
>> + if (!is_cxl_port(dev))
>> + return 0;
>> +
>> + port = to_cxl_port(dev);
>> +
>> + return port->parent_dport->dport_dev == dport_dev;
>> +}
>> +
>> +static void cxl_walk_port(struct device *port_dev,
>> + int (*cb)(struct device *, void *),
>> + void *userdata)
>> +{
>> + struct cxl_dport *dport = NULL;
>> + struct cxl_port *port;
>> + unsigned long index;
>> +
>> + if (!port_dev)
>> + return;
>> +
>> + port = to_cxl_port(port_dev);
>> + if (port->uport_dev && dev_is_pci(port->uport_dev))
>> + cb(port->uport_dev, userdata);
> Could use some comments on what is being walked. Also an explanation of what is happening here would be good.
Ok
> If this is an endpoint port, this would be the PCI endpoint device.
> If it's a switch port, then this is the upstream port.
> If it's a root port, this is skipped.
>
>> +
>> + xa_for_each(&port->dports, index, dport)
>> + {
>> + struct device *child_port_dev __free(put_device) =
>> + bus_find_device(&cxl_bus_type, &port->dev, dport->dport_dev,
>> + match_port_by_parent_dport);
>> +
>> + cb(dport->dport_dev, userdata);
> This is going through all the downstream ports
>> +
>> + cxl_walk_port(child_port_dev, cxl_report_error_detected, userdata);
>> + }
>> +
>> + if (is_cxl_endpoint(port))
>> + cb(port->uport_dev->parent, userdata);
> And this is the downstream parent port of the endpoint device
>
> Why not move this before the xa_for_each() and return early? endpoint ports don't have dports, no need to even try to run that block above.
Sure, I'll change that.
> So in the current implementation,
> 1. Endpoint. It checks the device, and then it checks the downstream parent port for errors. Is checking the parent dport necessary?
> 2. Switch. It checks the upstream port, then it checks all the downstream ports for errors.
> 3. Root port. It checks all the downstream ports for errors.
> Is this the correct understanding of what this function does?
Yes. The ordering is different as you pointed out. I can move the endpoint
check earlier with an early return.
>> +}
>> +
>> static void cxl_do_recovery(struct device *dev)
>> {
>> + pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
>> + struct pci_dev *pdev = to_pci_dev(dev);
>> + struct cxl_port *port = NULL;
>> +
>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM)) {
>> + struct cxl_dport *dport;
>> + struct cxl_port *rp_port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
>> +
>> + port = rp_port;
>> +
>> + } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_UPSTREAM) {
>> + struct cxl_port *us_port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
>> +
>> + port = us_port;
>> +
>> + } else if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
>> + struct cxl_dev_state *cxlds;
>> +
>> + if (!cxl_pci_drv_bound(pdev))
>> + return;
> Need to have the pci dev lock before checking driver bound.
> DJ
Ok, I'll try to add that into cxl_pci_drv_bound(). Terry
>> +
>> + cxlds = pci_get_drvdata(pdev);
>> + port = cxlds->cxlmd->endpoint;
>> + }
>> +
>> + if (!port) {
>> + dev_err(dev, "Failed to find the CXL device\n");
>> + return;
>> + }
>> +
>> + cxl_walk_port(&port->dev, cxl_report_error_detected, &status);
>> + if (status == PCI_ERS_RESULT_PANIC)
>> + panic("CXL cachemem error.");
>> +
>> + /*
>> + * If we have native control of AER, clear error status in the device
>> + * that detected the error. If the platform retained control of AER,
>> + * it is responsible for clearing this status. In that case, the
>> + * signaling device may not even be visible to the OS.
>> + */
>> + if (cxl_error_is_native(pdev)) {
>> + pcie_clear_device_status(pdev);
>> + pci_aer_clear_nonfatal_status(pdev);
>> + pci_aer_clear_fatal_status(pdev);
>> + }
>> }
>>
>> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
2025-09-30 14:38 ` Bowman, Terry
@ 2025-09-30 16:13 ` Dave Jiang
2025-09-30 16:43 ` Bowman, Terry
0 siblings, 1 reply; 92+ messages in thread
From: Dave Jiang @ 2025-09-30 16:13 UTC (permalink / raw)
To: Bowman, Terry, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/30/25 7:38 AM, Bowman, Terry wrote:
>
>
> On 9/29/2025 7:26 PM, Dave Jiang wrote:
>>
>> On 9/25/25 3:34 PM, Terry Bowman wrote:
>>> Populate the cxl_do_recovery() function with uncorrectable protocol error (UCE)
>>> handling. Follow similar design as found in PCIe error driver,
>>> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
>>> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>>>
>>> Introduce cxl_walk_port(). Make this analogous to pci_walk_bridge() but walking
>>> CXL ports instead. This will iterate through the CXL topology from the
>>> erroring device through the downstream CXL Ports and Endpoints.
>>>
>>> Export pci_aer_clear_fatal_status() for CXL to use if a UCE is not found.
>>>
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>>
>>> ---
>>>
>>> Changes in v11->v12:
>>> - Cleaned up port discovery in cxl_do_recovery() (Dave)
>>> - Added PCI_EXP_TYPE_RC_END to type check in cxl_report_error_detected()
>>>
>>> Changes in v10->v11:
>>> - pci_ers_merge_results() - Move to earlier patch
>>> ---
>>> drivers/cxl/core/ras.c | 111 +++++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 111 insertions(+)
>>>
>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>> index 7e8d63c32d72..45f92defca64 100644
>>> --- a/drivers/cxl/core/ras.c
>>> +++ b/drivers/cxl/core/ras.c
>>> @@ -443,8 +443,119 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
>>> }
>>> EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>>>
>>> +static int cxl_report_error_detected(struct device *dev, void *data)
>>> +{
>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>> + pci_ers_result_t vote, *result = data;
>>> +
>>> + guard(device)(dev);
>>> +
>>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
>>> + if (!cxl_pci_drv_bound(pdev))
>>> + return 0;
>>> +
>>> + vote = cxl_error_detected(dev);
>>> + } else {
>>> + vote = cxl_port_error_detected(dev);
>>> + }
>>> +
>>> + *result = pci_ers_merge_result(*result, vote);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int match_port_by_parent_dport(struct device *dev, const void *dport_dev)
>>> +{
>>> + struct cxl_port *port;
>>> +
>>> + if (!is_cxl_port(dev))
>>> + return 0;
>>> +
>>> + port = to_cxl_port(dev);
>>> +
>>> + return port->parent_dport->dport_dev == dport_dev;
>>> +}
>>> +
>>> +static void cxl_walk_port(struct device *port_dev,
>>> + int (*cb)(struct device *, void *),
>>> + void *userdata)
>>> +{
>>> + struct cxl_dport *dport = NULL;
>>> + struct cxl_port *port;
>>> + unsigned long index;
>>> +
>>> + if (!port_dev)
>>> + return;
>>> +
>>> + port = to_cxl_port(port_dev);
>>> + if (port->uport_dev && dev_is_pci(port->uport_dev))
>>> + cb(port->uport_dev, userdata);
>> Could use some comments on what is being walked. Also an explanation of what is happening here would be good.
> Ok
>> If this is an endpoint port, this would be the PCI endpoint device.
>> If it's a switch port, then this is the upstream port.
>> If it's a root port, this is skipped.
>>
>>> +
>>> + xa_for_each(&port->dports, index, dport)
>>> + {
>>> + struct device *child_port_dev __free(put_device) =
>>> + bus_find_device(&cxl_bus_type, &port->dev, dport->dport_dev,
>>> + match_port_by_parent_dport);
>>> +
>>> + cb(dport->dport_dev, userdata);
>> This is going through all the downstream ports
>>> +
>>> + cxl_walk_port(child_port_dev, cxl_report_error_detected, userdata);
>>> + }
>>> +
>>> + if (is_cxl_endpoint(port))
>>> + cb(port->uport_dev->parent, userdata);
>> And this is the downstream parent port of the endpoint device
>>
>> Why not move this before the xa_for_each() and return early? endpoint ports don't have dports, no need to even try to run that block above.
> Sure, I'll change that.
>> So in the current implementation,
>> 1. Endpoint. It checks the device, and then it checks the downstream parent port for errors. Is checking the parent dport necessary?
>> 2. Switch. It checks the upstream port, then it checks all the downstream ports for errors.
>> 3. Root port. It checks all the downstream ports for errors.
>> Is this the correct understanding of what this function does?
>
> Yes. The ordering is different as you pointed out. I can move the endpoint
> check earlier with an early return.
As the endpoint, what is the reason the check the parent dport? Pardon my ignorance.
>>> +}
>>> +
>>> static void cxl_do_recovery(struct device *dev)
>>> {
>>> + pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>> + struct cxl_port *port = NULL;
>>> +
>>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM)) {
>>> + struct cxl_dport *dport;
>>> + struct cxl_port *rp_port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
>>> +
>>> + port = rp_port;
>>> +
>>> + } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_UPSTREAM) {
>>> + struct cxl_port *us_port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
>>> +
>>> + port = us_port;
>>> +
>>> + } else if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
>>> + struct cxl_dev_state *cxlds;
>>> +
>>> + if (!cxl_pci_drv_bound(pdev))
>>> + return;
>> Need to have the pci dev lock before checking driver bound.
>> DJ
>
> Ok, I'll try to add that into cxl_pci_drv_bound(). Terry
Do you need the lock beyond just checking the driver data? Maybe do it outside cxl_pci_drv_bound(). I would have an assert in the function though to ensure lock is held when calling this function.
DJ
>>> +
>>> + cxlds = pci_get_drvdata(pdev);
>>> + port = cxlds->cxlmd->endpoint;
>>> + }
>>> +
>>> + if (!port) {
>>> + dev_err(dev, "Failed to find the CXL device\n");
>>> + return;
>>> + }
>>> +
>>> + cxl_walk_port(&port->dev, cxl_report_error_detected, &status);
>>> + if (status == PCI_ERS_RESULT_PANIC)
>>> + panic("CXL cachemem error.");
>>> +
>>> + /*
>>> + * If we have native control of AER, clear error status in the device
>>> + * that detected the error. If the platform retained control of AER,
>>> + * it is responsible for clearing this status. In that case, the
>>> + * signaling device may not even be visible to the OS.
>>> + */
>>> + if (cxl_error_is_native(pdev)) {
>>> + pcie_clear_device_status(pdev);
>>> + pci_aer_clear_nonfatal_status(pdev);
>>> + pci_aer_clear_fatal_status(pdev);
>>> + }
>>> }
>>>
>>> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>
>
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
2025-09-30 16:13 ` Dave Jiang
@ 2025-09-30 16:43 ` Bowman, Terry
2025-09-30 16:46 ` Dave Jiang
0 siblings, 1 reply; 92+ messages in thread
From: Bowman, Terry @ 2025-09-30 16:43 UTC (permalink / raw)
To: Dave Jiang, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/30/2025 11:13 AM, Dave Jiang wrote:
>
> On 9/30/25 7:38 AM, Bowman, Terry wrote:
>>
>> On 9/29/2025 7:26 PM, Dave Jiang wrote:
>>> On 9/25/25 3:34 PM, Terry Bowman wrote:
>>>> Populate the cxl_do_recovery() function with uncorrectable protocol error (UCE)
>>>> handling. Follow similar design as found in PCIe error driver,
>>>> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
>>>> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>>>>
>>>> Introduce cxl_walk_port(). Make this analogous to pci_walk_bridge() but walking
>>>> CXL ports instead. This will iterate through the CXL topology from the
>>>> erroring device through the downstream CXL Ports and Endpoints.
>>>>
>>>> Export pci_aer_clear_fatal_status() for CXL to use if a UCE is not found.
>>>>
>>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>>>
>>>> ---
>>>>
>>>> Changes in v11->v12:
>>>> - Cleaned up port discovery in cxl_do_recovery() (Dave)
>>>> - Added PCI_EXP_TYPE_RC_END to type check in cxl_report_error_detected()
>>>>
>>>> Changes in v10->v11:
>>>> - pci_ers_merge_results() - Move to earlier patch
>>>> ---
>>>> drivers/cxl/core/ras.c | 111 +++++++++++++++++++++++++++++++++++++++++
>>>> 1 file changed, 111 insertions(+)
>>>>
>>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>>> index 7e8d63c32d72..45f92defca64 100644
>>>> --- a/drivers/cxl/core/ras.c
>>>> +++ b/drivers/cxl/core/ras.c
>>>> @@ -443,8 +443,119 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
>>>> }
>>>> EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>>>>
>>>> +static int cxl_report_error_detected(struct device *dev, void *data)
>>>> +{
>>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>>> + pci_ers_result_t vote, *result = data;
>>>> +
>>>> + guard(device)(dev);
>>>> +
>>>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
>>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
>>>> + if (!cxl_pci_drv_bound(pdev))
>>>> + return 0;
>>>> +
>>>> + vote = cxl_error_detected(dev);
>>>> + } else {
>>>> + vote = cxl_port_error_detected(dev);
>>>> + }
>>>> +
>>>> + *result = pci_ers_merge_result(*result, vote);
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int match_port_by_parent_dport(struct device *dev, const void *dport_dev)
>>>> +{
>>>> + struct cxl_port *port;
>>>> +
>>>> + if (!is_cxl_port(dev))
>>>> + return 0;
>>>> +
>>>> + port = to_cxl_port(dev);
>>>> +
>>>> + return port->parent_dport->dport_dev == dport_dev;
>>>> +}
>>>> +
>>>> +static void cxl_walk_port(struct device *port_dev,
>>>> + int (*cb)(struct device *, void *),
>>>> + void *userdata)
>>>> +{
>>>> + struct cxl_dport *dport = NULL;
>>>> + struct cxl_port *port;
>>>> + unsigned long index;
>>>> +
>>>> + if (!port_dev)
>>>> + return;
>>>> +
>>>> + port = to_cxl_port(port_dev);
>>>> + if (port->uport_dev && dev_is_pci(port->uport_dev))
>>>> + cb(port->uport_dev, userdata);
>>> Could use some comments on what is being walked. Also an explanation of what is happening here would be good.
>> Ok
>>> If this is an endpoint port, this would be the PCI endpoint device.
>>> If it's a switch port, then this is the upstream port.
>>> If it's a root port, this is skipped.
>>>
>>>> +
>>>> + xa_for_each(&port->dports, index, dport)
>>>> + {
>>>> + struct device *child_port_dev __free(put_device) =
>>>> + bus_find_device(&cxl_bus_type, &port->dev, dport->dport_dev,
>>>> + match_port_by_parent_dport);
>>>> +
>>>> + cb(dport->dport_dev, userdata);
>>> This is going through all the downstream ports
>>>> +
>>>> + cxl_walk_port(child_port_dev, cxl_report_error_detected, userdata);
>>>> + }
>>>> +
>>>> + if (is_cxl_endpoint(port))
>>>> + cb(port->uport_dev->parent, userdata);
>>> And this is the downstream parent port of the endpoint device
>>>
>>> Why not move this before the xa_for_each() and return early? endpoint ports don't have dports, no need to even try to run that block above.
>> Sure, I'll change that.
>>> So in the current implementation,
>>> 1. Endpoint. It checks the device, and then it checks the downstream parent port for errors. Is checking the parent dport necessary?
>>> 2. Switch. It checks the upstream port, then it checks all the downstream ports for errors.
>>> 3. Root port. It checks all the downstream ports for errors.
>>> Is this the correct understanding of what this function does?
>> Yes. The ordering is different as you pointed out. I can move the endpoint
>> check earlier with an early return.
> As the endpoint, what is the reason the check the parent dport? Pardon my ignorance.
There is none. An endpoint port will not have downstream ports.
>>>> +}
>>>> +
>>>> static void cxl_do_recovery(struct device *dev)
>>>> {
>>>> + pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
>>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>>> + struct cxl_port *port = NULL;
>>>> +
>>>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
>>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM)) {
>>>> + struct cxl_dport *dport;
>>>> + struct cxl_port *rp_port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
>>>> +
>>>> + port = rp_port;
>>>> +
>>>> + } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_UPSTREAM) {
>>>> + struct cxl_port *us_port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
>>>> +
>>>> + port = us_port;
>>>> +
>>>> + } else if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
>>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
>>>> + struct cxl_dev_state *cxlds;
>>>> +
>>>> + if (!cxl_pci_drv_bound(pdev))
>>>> + return;
>>> Need to have the pci dev lock before checking driver bound.
>>> DJ
>> Ok, I'll try to add that into cxl_pci_drv_bound(). Terry
> Do you need the lock beyond just checking the driver data? Maybe do it outside cxl_pci_drv_bound(). I would have an assert in the function though to ensure lock is held when calling this function.
Ok, good idea.
Terry
> DJ
>>>> +
>>>> + cxlds = pci_get_drvdata(pdev);
>>>> + port = cxlds->cxlmd->endpoint;
>>>> + }
>>>> +
>>>> + if (!port) {
>>>> + dev_err(dev, "Failed to find the CXL device\n");
>>>> + return;
>>>> + }
>>>> +
>>>> + cxl_walk_port(&port->dev, cxl_report_error_detected, &status);
>>>> + if (status == PCI_ERS_RESULT_PANIC)
>>>> + panic("CXL cachemem error.");
>>>> +
>>>> + /*
>>>> + * If we have native control of AER, clear error status in the device
>>>> + * that detected the error. If the platform retained control of AER,
>>>> + * it is responsible for clearing this status. In that case, the
>>>> + * signaling device may not even be visible to the OS.
>>>> + */
>>>> + if (cxl_error_is_native(pdev)) {
>>>> + pcie_clear_device_status(pdev);
>>>> + pci_aer_clear_nonfatal_status(pdev);
>>>> + pci_aer_clear_fatal_status(pdev);
>>>> + }
>>>> }
>>>>
>>>> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>>
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
2025-09-30 16:43 ` Bowman, Terry
@ 2025-09-30 16:46 ` Dave Jiang
2025-10-01 13:58 ` Bowman, Terry
0 siblings, 1 reply; 92+ messages in thread
From: Dave Jiang @ 2025-09-30 16:46 UTC (permalink / raw)
To: Bowman, Terry, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/30/25 9:43 AM, Bowman, Terry wrote:
>
>
> On 9/30/2025 11:13 AM, Dave Jiang wrote:
>>
>> On 9/30/25 7:38 AM, Bowman, Terry wrote:
>>>
>>> On 9/29/2025 7:26 PM, Dave Jiang wrote:
>>>> On 9/25/25 3:34 PM, Terry Bowman wrote:
>>>>> Populate the cxl_do_recovery() function with uncorrectable protocol error (UCE)
>>>>> handling. Follow similar design as found in PCIe error driver,
>>>>> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
>>>>> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>>>>>
>>>>> Introduce cxl_walk_port(). Make this analogous to pci_walk_bridge() but walking
>>>>> CXL ports instead. This will iterate through the CXL topology from the
>>>>> erroring device through the downstream CXL Ports and Endpoints.
>>>>>
>>>>> Export pci_aer_clear_fatal_status() for CXL to use if a UCE is not found.
>>>>>
>>>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>>>>
>>>>> ---
>>>>>
>>>>> Changes in v11->v12:
>>>>> - Cleaned up port discovery in cxl_do_recovery() (Dave)
>>>>> - Added PCI_EXP_TYPE_RC_END to type check in cxl_report_error_detected()
>>>>>
>>>>> Changes in v10->v11:
>>>>> - pci_ers_merge_results() - Move to earlier patch
>>>>> ---
>>>>> drivers/cxl/core/ras.c | 111 +++++++++++++++++++++++++++++++++++++++++
>>>>> 1 file changed, 111 insertions(+)
>>>>>
>>>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>>>> index 7e8d63c32d72..45f92defca64 100644
>>>>> --- a/drivers/cxl/core/ras.c
>>>>> +++ b/drivers/cxl/core/ras.c
>>>>> @@ -443,8 +443,119 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
>>>>> }
>>>>> EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>>>>>
>>>>> +static int cxl_report_error_detected(struct device *dev, void *data)
>>>>> +{
>>>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>>>> + pci_ers_result_t vote, *result = data;
>>>>> +
>>>>> + guard(device)(dev);
>>>>> +
>>>>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
>>>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
>>>>> + if (!cxl_pci_drv_bound(pdev))
>>>>> + return 0;
>>>>> +
>>>>> + vote = cxl_error_detected(dev);
>>>>> + } else {
>>>>> + vote = cxl_port_error_detected(dev);
>>>>> + }
>>>>> +
>>>>> + *result = pci_ers_merge_result(*result, vote);
>>>>> +
>>>>> + return 0;
>>>>> +}
>>>>> +
>>>>> +static int match_port_by_parent_dport(struct device *dev, const void *dport_dev)
>>>>> +{
>>>>> + struct cxl_port *port;
>>>>> +
>>>>> + if (!is_cxl_port(dev))
>>>>> + return 0;
>>>>> +
>>>>> + port = to_cxl_port(dev);
>>>>> +
>>>>> + return port->parent_dport->dport_dev == dport_dev;
>>>>> +}
>>>>> +
>>>>> +static void cxl_walk_port(struct device *port_dev,
>>>>> + int (*cb)(struct device *, void *),
>>>>> + void *userdata)
>>>>> +{
>>>>> + struct cxl_dport *dport = NULL;
>>>>> + struct cxl_port *port;
>>>>> + unsigned long index;
>>>>> +
>>>>> + if (!port_dev)
>>>>> + return;
>>>>> +
>>>>> + port = to_cxl_port(port_dev);
>>>>> + if (port->uport_dev && dev_is_pci(port->uport_dev))
>>>>> + cb(port->uport_dev, userdata);
>>>> Could use some comments on what is being walked. Also an explanation of what is happening here would be good.
>>> Ok
>>>> If this is an endpoint port, this would be the PCI endpoint device.
>>>> If it's a switch port, then this is the upstream port.
>>>> If it's a root port, this is skipped.
>>>>
>>>>> +
>>>>> + xa_for_each(&port->dports, index, dport)
>>>>> + {
>>>>> + struct device *child_port_dev __free(put_device) =
>>>>> + bus_find_device(&cxl_bus_type, &port->dev, dport->dport_dev,
>>>>> + match_port_by_parent_dport);
>>>>> +
>>>>> + cb(dport->dport_dev, userdata);
>>>> This is going through all the downstream ports
>>>>> +
>>>>> + cxl_walk_port(child_port_dev, cxl_report_error_detected, userdata);
>>>>> + }
>>>>> +
>>>>> + if (is_cxl_endpoint(port))
>>>>> + cb(port->uport_dev->parent, userdata);
>>>> And this is the downstream parent port of the endpoint device
>>>>
>>>> Why not move this before the xa_for_each() and return early? endpoint ports don't have dports, no need to even try to run that block above.
>>> Sure, I'll change that.
>>>> So in the current implementation,
>>>> 1. Endpoint. It checks the device, and then it checks the downstream parent port for errors. Is checking the parent dport necessary?
>>>> 2. Switch. It checks the upstream port, then it checks all the downstream ports for errors.
>>>> 3. Root port. It checks all the downstream ports for errors.
>>>> Is this the correct understanding of what this function does?
>>> Yes. The ordering is different as you pointed out. I can move the endpoint
>>> check earlier with an early return.
>> As the endpoint, what is the reason the check the parent dport? Pardon my ignorance.
>
> There is none. An endpoint port will not have downstream ports.
parent dport. It would be the root port or the switch downstream port. This is what the current code is doing:
>>>>> + if (is_cxl_endpoint(port))
>>>>> + cb(port->uport_dev->parent, userdata);
DJ
>
>>>>> +}
>>>>> +
>>>>> static void cxl_do_recovery(struct device *dev)
>>>>> {
>>>>> + pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
>>>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>>>> + struct cxl_port *port = NULL;
>>>>> +
>>>>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
>>>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM)) {
>>>>> + struct cxl_dport *dport;
>>>>> + struct cxl_port *rp_port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
>>>>> +
>>>>> + port = rp_port;
>>>>> +
>>>>> + } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_UPSTREAM) {
>>>>> + struct cxl_port *us_port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
>>>>> +
>>>>> + port = us_port;
>>>>> +
>>>>> + } else if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
>>>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
>>>>> + struct cxl_dev_state *cxlds;
>>>>> +
>>>>> + if (!cxl_pci_drv_bound(pdev))
>>>>> + return;
>>>> Need to have the pci dev lock before checking driver bound.
>>>> DJ
>>> Ok, I'll try to add that into cxl_pci_drv_bound(). Terry
>> Do you need the lock beyond just checking the driver data? Maybe do it outside cxl_pci_drv_bound(). I would have an assert in the function though to ensure lock is held when calling this function.
>
> Ok, good idea.
>
> Terry
>> DJ
>>>>> +
>>>>> + cxlds = pci_get_drvdata(pdev);
>>>>> + port = cxlds->cxlmd->endpoint;
>>>>> + }
>>>>> +
>>>>> + if (!port) {
>>>>> + dev_err(dev, "Failed to find the CXL device\n");
>>>>> + return;
>>>>> + }
>>>>> +
>>>>> + cxl_walk_port(&port->dev, cxl_report_error_detected, &status);
>>>>> + if (status == PCI_ERS_RESULT_PANIC)
>>>>> + panic("CXL cachemem error.");
>>>>> +
>>>>> + /*
>>>>> + * If we have native control of AER, clear error status in the device
>>>>> + * that detected the error. If the platform retained control of AER,
>>>>> + * it is responsible for clearing this status. In that case, the
>>>>> + * signaling device may not even be visible to the OS.
>>>>> + */
>>>>> + if (cxl_error_is_native(pdev)) {
>>>>> + pcie_clear_device_status(pdev);
>>>>> + pci_aer_clear_nonfatal_status(pdev);
>>>>> + pci_aer_clear_fatal_status(pdev);
>>>>> + }
>>>>> }
>>>>>
>>>>> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
>>>
>
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
2025-09-30 16:46 ` Dave Jiang
@ 2025-10-01 13:58 ` Bowman, Terry
2025-10-01 15:33 ` Dave Jiang
0 siblings, 1 reply; 92+ messages in thread
From: Bowman, Terry @ 2025-10-01 13:58 UTC (permalink / raw)
To: Dave Jiang, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/30/2025 11:46 AM, Dave Jiang wrote:
>
> On 9/30/25 9:43 AM, Bowman, Terry wrote:
>>
>> On 9/30/2025 11:13 AM, Dave Jiang wrote:
>>> On 9/30/25 7:38 AM, Bowman, Terry wrote:
>>>> On 9/29/2025 7:26 PM, Dave Jiang wrote:
>>>>> On 9/25/25 3:34 PM, Terry Bowman wrote:
>>>>>> Populate the cxl_do_recovery() function with uncorrectable protocol error (UCE)
>>>>>> handling. Follow similar design as found in PCIe error driver,
>>>>>> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
>>>>>> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>>>>>>
>>>>>> Introduce cxl_walk_port(). Make this analogous to pci_walk_bridge() but walking
>>>>>> CXL ports instead. This will iterate through the CXL topology from the
>>>>>> erroring device through the downstream CXL Ports and Endpoints.
>>>>>>
>>>>>> Export pci_aer_clear_fatal_status() for CXL to use if a UCE is not found.
>>>>>>
>>>>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>>>>>
>>>>>> ---
>>>>>>
>>>>>> Changes in v11->v12:
>>>>>> - Cleaned up port discovery in cxl_do_recovery() (Dave)
>>>>>> - Added PCI_EXP_TYPE_RC_END to type check in cxl_report_error_detected()
>>>>>>
>>>>>> Changes in v10->v11:
>>>>>> - pci_ers_merge_results() - Move to earlier patch
>>>>>> ---
>>>>>> drivers/cxl/core/ras.c | 111 +++++++++++++++++++++++++++++++++++++++++
>>>>>> 1 file changed, 111 insertions(+)
>>>>>>
>>>>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>>>>> index 7e8d63c32d72..45f92defca64 100644
>>>>>> --- a/drivers/cxl/core/ras.c
>>>>>> +++ b/drivers/cxl/core/ras.c
>>>>>> @@ -443,8 +443,119 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
>>>>>> }
>>>>>> EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>>>>>>
>>>>>> +static int cxl_report_error_detected(struct device *dev, void *data)
>>>>>> +{
>>>>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>>>>> + pci_ers_result_t vote, *result = data;
>>>>>> +
>>>>>> + guard(device)(dev);
>>>>>> +
>>>>>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
>>>>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
>>>>>> + if (!cxl_pci_drv_bound(pdev))
>>>>>> + return 0;
>>>>>> +
>>>>>> + vote = cxl_error_detected(dev);
>>>>>> + } else {
>>>>>> + vote = cxl_port_error_detected(dev);
>>>>>> + }
>>>>>> +
>>>>>> + *result = pci_ers_merge_result(*result, vote);
>>>>>> +
>>>>>> + return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static int match_port_by_parent_dport(struct device *dev, const void *dport_dev)
>>>>>> +{
>>>>>> + struct cxl_port *port;
>>>>>> +
>>>>>> + if (!is_cxl_port(dev))
>>>>>> + return 0;
>>>>>> +
>>>>>> + port = to_cxl_port(dev);
>>>>>> +
>>>>>> + return port->parent_dport->dport_dev == dport_dev;
>>>>>> +}
>>>>>> +
>>>>>> +static void cxl_walk_port(struct device *port_dev,
>>>>>> + int (*cb)(struct device *, void *),
>>>>>> + void *userdata)
>>>>>> +{
>>>>>> + struct cxl_dport *dport = NULL;
>>>>>> + struct cxl_port *port;
>>>>>> + unsigned long index;
>>>>>> +
>>>>>> + if (!port_dev)
>>>>>> + return;
>>>>>> +
>>>>>> + port = to_cxl_port(port_dev);
>>>>>> + if (port->uport_dev && dev_is_pci(port->uport_dev))
>>>>>> + cb(port->uport_dev, userdata);
>>>>> Could use some comments on what is being walked. Also an explanation of what is happening here would be good.
>>>> Ok
>>>>> If this is an endpoint port, this would be the PCI endpoint device.
>>>>> If it's a switch port, then this is the upstream port.
>>>>> If it's a root port, this is skipped.
>>>>>
>>>>>> +
>>>>>> + xa_for_each(&port->dports, index, dport)
>>>>>> + {
>>>>>> + struct device *child_port_dev __free(put_device) =
>>>>>> + bus_find_device(&cxl_bus_type, &port->dev, dport->dport_dev,
>>>>>> + match_port_by_parent_dport);
>>>>>> +
>>>>>> + cb(dport->dport_dev, userdata);
>>>>> This is going through all the downstream ports
>>>>>> +
>>>>>> + cxl_walk_port(child_port_dev, cxl_report_error_detected, userdata);
>>>>>> + }
>>>>>> +
>>>>>> + if (is_cxl_endpoint(port))
>>>>>> + cb(port->uport_dev->parent, userdata);
>>>>> And this is the downstream parent port of the endpoint device
>>>>>
>>>>> Why not move this before the xa_for_each() and return early? endpoint ports don't have dports, no need to even try to run that block above.
>>>> Sure, I'll change that.
>>>>> So in the current implementation,
>>>>> 1. Endpoint. It checks the device, and then it checks the downstream parent port for errors. Is checking the parent dport necessary?
>>>>> 2. Switch. It checks the upstream port, then it checks all the downstream ports for errors.
>>>>> 3. Root port. It checks all the downstream ports for errors.
>>>>> Is this the correct understanding of what this function does?
>>>> Yes. The ordering is different as you pointed out. I can move the endpoint
>>>> check earlier with an early return.
>>> As the endpoint, what is the reason the check the parent dport? Pardon my ignorance.
>> There is none. An endpoint port will not have downstream ports.
> parent dport. It would be the root port or the switch downstream port. This is what the current code is doing:
>
>>>>>> + if (is_cxl_endpoint(port))
>>>>>> + cb(port->uport_dev->parent, userdata);
> DJ
>
>
Yes. I need to change port->uport_dev->parent to be port->uport_dev. Thanks. Terry
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
2025-10-01 13:58 ` Bowman, Terry
@ 2025-10-01 15:33 ` Dave Jiang
0 siblings, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-10-01 15:33 UTC (permalink / raw)
To: Bowman, Terry, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 10/1/25 6:58 AM, Bowman, Terry wrote:
>
>
> On 9/30/2025 11:46 AM, Dave Jiang wrote:
>>
>> On 9/30/25 9:43 AM, Bowman, Terry wrote:
>>>
>>> On 9/30/2025 11:13 AM, Dave Jiang wrote:
>>>> On 9/30/25 7:38 AM, Bowman, Terry wrote:
>>>>> On 9/29/2025 7:26 PM, Dave Jiang wrote:
>>>>>> On 9/25/25 3:34 PM, Terry Bowman wrote:
>>>>>>> Populate the cxl_do_recovery() function with uncorrectable protocol error (UCE)
>>>>>>> handling. Follow similar design as found in PCIe error driver,
>>>>>>> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
>>>>>>> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>>>>>>>
>>>>>>> Introduce cxl_walk_port(). Make this analogous to pci_walk_bridge() but walking
>>>>>>> CXL ports instead. This will iterate through the CXL topology from the
>>>>>>> erroring device through the downstream CXL Ports and Endpoints.
>>>>>>>
>>>>>>> Export pci_aer_clear_fatal_status() for CXL to use if a UCE is not found.
>>>>>>>
>>>>>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>>>>>>
>>>>>>> ---
>>>>>>>
>>>>>>> Changes in v11->v12:
>>>>>>> - Cleaned up port discovery in cxl_do_recovery() (Dave)
>>>>>>> - Added PCI_EXP_TYPE_RC_END to type check in cxl_report_error_detected()
>>>>>>>
>>>>>>> Changes in v10->v11:
>>>>>>> - pci_ers_merge_results() - Move to earlier patch
>>>>>>> ---
>>>>>>> drivers/cxl/core/ras.c | 111 +++++++++++++++++++++++++++++++++++++++++
>>>>>>> 1 file changed, 111 insertions(+)
>>>>>>>
>>>>>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>>>>>> index 7e8d63c32d72..45f92defca64 100644
>>>>>>> --- a/drivers/cxl/core/ras.c
>>>>>>> +++ b/drivers/cxl/core/ras.c
>>>>>>> @@ -443,8 +443,119 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
>>>>>>> }
>>>>>>> EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>>>>>>>
>>>>>>> +static int cxl_report_error_detected(struct device *dev, void *data)
>>>>>>> +{
>>>>>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>>>>>> + pci_ers_result_t vote, *result = data;
>>>>>>> +
>>>>>>> + guard(device)(dev);
>>>>>>> +
>>>>>>> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
>>>>>>> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
>>>>>>> + if (!cxl_pci_drv_bound(pdev))
>>>>>>> + return 0;
>>>>>>> +
>>>>>>> + vote = cxl_error_detected(dev);
>>>>>>> + } else {
>>>>>>> + vote = cxl_port_error_detected(dev);
>>>>>>> + }
>>>>>>> +
>>>>>>> + *result = pci_ers_merge_result(*result, vote);
>>>>>>> +
>>>>>>> + return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +static int match_port_by_parent_dport(struct device *dev, const void *dport_dev)
>>>>>>> +{
>>>>>>> + struct cxl_port *port;
>>>>>>> +
>>>>>>> + if (!is_cxl_port(dev))
>>>>>>> + return 0;
>>>>>>> +
>>>>>>> + port = to_cxl_port(dev);
>>>>>>> +
>>>>>>> + return port->parent_dport->dport_dev == dport_dev;
>>>>>>> +}
>>>>>>> +
>>>>>>> +static void cxl_walk_port(struct device *port_dev,
>>>>>>> + int (*cb)(struct device *, void *),
>>>>>>> + void *userdata)
>>>>>>> +{
>>>>>>> + struct cxl_dport *dport = NULL;
>>>>>>> + struct cxl_port *port;
>>>>>>> + unsigned long index;
>>>>>>> +
>>>>>>> + if (!port_dev)
>>>>>>> + return;
>>>>>>> +
>>>>>>> + port = to_cxl_port(port_dev);
>>>>>>> + if (port->uport_dev && dev_is_pci(port->uport_dev))
>>>>>>> + cb(port->uport_dev, userdata);
>>>>>> Could use some comments on what is being walked. Also an explanation of what is happening here would be good.
>>>>> Ok
>>>>>> If this is an endpoint port, this would be the PCI endpoint device.
>>>>>> If it's a switch port, then this is the upstream port.
>>>>>> If it's a root port, this is skipped.
>>>>>>
>>>>>>> +
>>>>>>> + xa_for_each(&port->dports, index, dport)
>>>>>>> + {
>>>>>>> + struct device *child_port_dev __free(put_device) =
>>>>>>> + bus_find_device(&cxl_bus_type, &port->dev, dport->dport_dev,
>>>>>>> + match_port_by_parent_dport);
>>>>>>> +
>>>>>>> + cb(dport->dport_dev, userdata);
>>>>>> This is going through all the downstream ports
>>>>>>> +
>>>>>>> + cxl_walk_port(child_port_dev, cxl_report_error_detected, userdata);
>>>>>>> + }
>>>>>>> +
>>>>>>> + if (is_cxl_endpoint(port))
>>>>>>> + cb(port->uport_dev->parent, userdata);
>>>>>> And this is the downstream parent port of the endpoint device
>>>>>>
>>>>>> Why not move this before the xa_for_each() and return early? endpoint ports don't have dports, no need to even try to run that block above.
>>>>> Sure, I'll change that.
>>>>>> So in the current implementation,
>>>>>> 1. Endpoint. It checks the device, and then it checks the downstream parent port for errors. Is checking the parent dport necessary?
>>>>>> 2. Switch. It checks the upstream port, then it checks all the downstream ports for errors.
>>>>>> 3. Root port. It checks all the downstream ports for errors.
>>>>>> Is this the correct understanding of what this function does?
>>>>> Yes. The ordering is different as you pointed out. I can move the endpoint
>>>>> check earlier with an early return.
>>>> As the endpoint, what is the reason the check the parent dport? Pardon my ignorance.
>>> There is none. An endpoint port will not have downstream ports.
>> parent dport. It would be the root port or the switch downstream port. This is what the current code is doing:
>>
>>>>>>> + if (is_cxl_endpoint(port))
>>>>>>> + cb(port->uport_dev->parent, userdata);
>> DJ
>>
>>
>
> Yes. I need to change port->uport_dev->parent to be port->uport_dev. Thanks. Terry
I believe your first chunk already covered the endpoint device:
>>>>>>> + if (port->uport_dev && dev_is_pci(port->uport_dev))
>>>>>>> + cb(port->uport_dev, userdata);
So you can probably just drop the last chunk entirely.
^ permalink raw reply [flat|nested] 92+ messages in thread
* Re: [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
2025-09-25 22:34 ` [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery Terry Bowman
2025-09-30 0:26 ` Dave Jiang
@ 2025-10-03 20:12 ` Cheatham, Benjamin
1 sibling, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:12 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> Populate the cxl_do_recovery() function with uncorrectable protocol error (UCE)
> handling. Follow similar design as found in PCIe error driver,
> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>
> Introduce cxl_walk_port(). Make this analogous to pci_walk_bridge() but walking
> CXL ports instead. This will iterate through the CXL topology from the
> erroring device through the downstream CXL Ports and Endpoints.
>
> Export pci_aer_clear_fatal_status() for CXL to use if a UCE is not found.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>
> ---
>
> Changes in v11->v12:
> - Cleaned up port discovery in cxl_do_recovery() (Dave)
> - Added PCI_EXP_TYPE_RC_END to type check in cxl_report_error_detected()
>
> Changes in v10->v11:
> - pci_ers_merge_results() - Move to earlier patch
> ---
> drivers/cxl/core/ras.c | 111 +++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 111 insertions(+)
>
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 7e8d63c32d72..45f92defca64 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -443,8 +443,119 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
> }
> EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>
> +static int cxl_report_error_detected(struct device *dev, void *data)
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
Should probably check if dev_is_pci() first. I don't think it's an issue since
only ports under the root dport are being iterated, but I don't know if this would
trip up cxl_test.
> + pci_ers_result_t vote, *result = data;
> +
> + guard(device)(dev);
> +
> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
> + if (!cxl_pci_drv_bound(pdev))
> + return 0;
> +
> + vote = cxl_error_detected(dev);
> + } else {
> + vote = cxl_port_error_detected(dev);
> + }
> +
> + *result = pci_ers_merge_result(*result, vote);
> +
> + return 0;
> +}
> +
> +static int match_port_by_parent_dport(struct device *dev, const void *dport_dev)
> +{
> + struct cxl_port *port;
> +
> + if (!is_cxl_port(dev))
> + return 0;
> +
> + port = to_cxl_port(dev);
> +
> + return port->parent_dport->dport_dev == dport_dev;
> +}
> +
> +static void cxl_walk_port(struct device *port_dev,
> + int (*cb)(struct device *, void *),
> + void *userdata)
This should just take a struct cxl_port * instead of device *. You always have the
struct cxl_port below and then pass in the &port->dev, only to just cast it back
to a struct cxl_port and never use the device pointer.
> +{
> + struct cxl_dport *dport = NULL;
> + struct cxl_port *port;
> + unsigned long index;
> +
> + if (!port_dev)
> + return;
> +
> + port = to_cxl_port(port_dev);
> + if (port->uport_dev && dev_is_pci(port->uport_dev))
> + cb(port->uport_dev, userdata);
> +
> + xa_for_each(&port->dports, index, dport)
> + {
> + struct device *child_port_dev __free(put_device) =
> + bus_find_device(&cxl_bus_type, &port->dev, dport->dport_dev,
> + match_port_by_parent_dport);
> +
> + cb(dport->dport_dev, userdata);
> +
> + cxl_walk_port(child_port_dev, cxl_report_error_detected, userdata);
> + }
> +
> + if (is_cxl_endpoint(port))
> + cb(port->uport_dev->parent, userdata);
> +}
> +
> static void cxl_do_recovery(struct device *dev)
> {
> + pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
> + struct pci_dev *pdev = to_pci_dev(dev);
> + struct cxl_port *port = NULL;
> +
> + if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) ||
> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM)) {
> + struct cxl_dport *dport;
> + struct cxl_port *rp_port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
> +
> + port = rp_port;
> +
> + } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_UPSTREAM) {
> + struct cxl_port *us_port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
> +
> + port = us_port;
> +
> + } else if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
> + (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
> + struct cxl_dev_state *cxlds;
> +
> + if (!cxl_pci_drv_bound(pdev))
> + return;
> +
> + cxlds = pci_get_drvdata(pdev);
> + port = cxlds->cxlmd->endpoint;
> + }
> +
> + if (!port) {
> + dev_err(dev, "Failed to find the CXL device\n");
> + return;
> + }
> +
> + cxl_walk_port(&port->dev, cxl_report_error_detected, &status);
> + if (status == PCI_ERS_RESULT_PANIC)
> + panic("CXL cachemem error.");
> +
> + /*
> + * If we have native control of AER, clear error status in the device
> + * that detected the error. If the platform retained control of AER,
> + * it is responsible for clearing this status. In that case, the
> + * signaling device may not even be visible to the OS.
> + */
> + if (cxl_error_is_native(pdev)) {
> + pcie_clear_device_status(pdev);
> + pci_aer_clear_nonfatal_status(pdev);
> + pci_aer_clear_fatal_status(pdev);
> + }
> }
>
> static void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 24/25] CXL/PCI: Enable CXL protocol errors during CXL Port probe
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (22 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 23/25] CXL/PCI: Introduce CXL uncorrectable protocol error recovery Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-09-30 0:28 ` Dave Jiang
2025-10-03 20:12 ` Cheatham, Benjamin
2025-09-25 22:34 ` [PATCH v12 25/25] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup Terry Bowman
24 siblings, 2 replies; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
CXL protocol errors are not enabled for all CXL devices after boot. These
must be enabled inorder to process CXL protocol errors.
Introduce cxl_unmask_proto_interrupts() to call pci_aer_unmask_internal_errors().
pci_aer_unmask_internal_errors() expects the pdev->aer_cap is initialized.
But, dev->aer_cap is not initialized for CXL Upstream Switch Ports and CXL
Downstream Switch Ports. Initialize the dev->aer_cap if necessary. Enable AER
correctable internal errors and uncorrectable internal errors for all CXL
devices.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
Changes in v11->v12:
- None
Changes in v10->v11:
- Added check for valid PCI devices in is_cxl_error() (Terry)
- Removed check for RCiEP in cxl_handle_proto_err() and
cxl_report_error_detected() (Terry)
---
drivers/cxl/core/ras.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 45f92defca64..ea65001daba1 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -238,6 +238,21 @@ static inline void cxl_disable_rch_root_ints(struct cxl_dport *dport) { }
static inline void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { }
#endif
+static void cxl_unmask_proto_interrupts(struct device *dev)
+{
+ struct pci_dev *pdev __free(pci_dev_put) =
+ pci_dev_get(to_pci_dev(dev));
+
+ if (!pdev->aer_cap) {
+ pdev->aer_cap = pci_find_ext_capability(pdev,
+ PCI_EXT_CAP_ID_ERR);
+ if (!pdev->aer_cap)
+ return;
+ }
+
+ pci_aer_unmask_internal_errors(pdev);
+}
+
static void cxl_dport_map_ras(struct cxl_dport *dport)
{
struct cxl_register_map *map = &dport->reg_map;
@@ -391,7 +406,10 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
cxl_dport_map_rch_aer(dport);
cxl_disable_rch_root_ints(dport);
+ return;
}
+
+ cxl_unmask_proto_interrupts(dport->dport_dev);
}
EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
@@ -402,8 +420,12 @@ static void cxl_uport_init_ras_reporting(struct cxl_port *port,
map->host = host;
if (cxl_map_component_regs(map, &port->uport_regs,
- BIT(CXL_CM_CAP_CAP_ID_RAS)))
+ BIT(CXL_CM_CAP_CAP_ID_RAS))) {
dev_dbg(&port->dev, "Failed to map RAS capability\n");
+ return;
+ }
+
+ cxl_unmask_proto_interrupts(port->uport_dev);
}
void cxl_switch_port_init_ras(struct cxl_port *port)
@@ -440,6 +462,8 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
}
cxl_dport_init_ras_reporting(parent_dport, cxlmd->cxlds->dev);
+
+ cxl_unmask_proto_interrupts(cxlmd->cxlds->dev);
}
EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 24/25] CXL/PCI: Enable CXL protocol errors during CXL Port probe
2025-09-25 22:34 ` [PATCH v12 24/25] CXL/PCI: Enable CXL protocol errors during CXL Port probe Terry Bowman
@ 2025-09-30 0:28 ` Dave Jiang
2025-10-03 20:12 ` Cheatham, Benjamin
1 sibling, 0 replies; 92+ messages in thread
From: Dave Jiang @ 2025-09-30 0:28 UTC (permalink / raw)
To: Terry Bowman, dave, jonathan.cameron, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci
On 9/25/25 3:34 PM, Terry Bowman wrote:
> CXL protocol errors are not enabled for all CXL devices after boot. These
> must be enabled inorder to process CXL protocol errors.
>
> Introduce cxl_unmask_proto_interrupts() to call pci_aer_unmask_internal_errors().
> pci_aer_unmask_internal_errors() expects the pdev->aer_cap is initialized.
> But, dev->aer_cap is not initialized for CXL Upstream Switch Ports and CXL
> Downstream Switch Ports. Initialize the dev->aer_cap if necessary. Enable AER
> correctable internal errors and uncorrectable internal errors for all CXL
> devices.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> ---
> Changes in v11->v12:
> - None
>
> Changes in v10->v11:
> - Added check for valid PCI devices in is_cxl_error() (Terry)
> - Removed check for RCiEP in cxl_handle_proto_err() and
> cxl_report_error_detected() (Terry)
> ---
> drivers/cxl/core/ras.c | 26 +++++++++++++++++++++++++-
> 1 file changed, 25 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 45f92defca64..ea65001daba1 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -238,6 +238,21 @@ static inline void cxl_disable_rch_root_ints(struct cxl_dport *dport) { }
> static inline void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { }
> #endif
>
> +static void cxl_unmask_proto_interrupts(struct device *dev)
> +{
> + struct pci_dev *pdev __free(pci_dev_put) =
> + pci_dev_get(to_pci_dev(dev));
> +
> + if (!pdev->aer_cap) {
> + pdev->aer_cap = pci_find_ext_capability(pdev,
> + PCI_EXT_CAP_ID_ERR);
> + if (!pdev->aer_cap)
> + return;
> + }
> +
> + pci_aer_unmask_internal_errors(pdev);
> +}
> +
> static void cxl_dport_map_ras(struct cxl_dport *dport)
> {
> struct cxl_register_map *map = &dport->reg_map;
> @@ -391,7 +406,10 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
>
> cxl_dport_map_rch_aer(dport);
> cxl_disable_rch_root_ints(dport);
> + return;
> }
> +
> + cxl_unmask_proto_interrupts(dport->dport_dev);
> }
> EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
>
> @@ -402,8 +420,12 @@ static void cxl_uport_init_ras_reporting(struct cxl_port *port,
>
> map->host = host;
> if (cxl_map_component_regs(map, &port->uport_regs,
> - BIT(CXL_CM_CAP_CAP_ID_RAS)))
> + BIT(CXL_CM_CAP_CAP_ID_RAS))) {
> dev_dbg(&port->dev, "Failed to map RAS capability\n");
> + return;
> + }
> +
> + cxl_unmask_proto_interrupts(port->uport_dev);
> }
>
> void cxl_switch_port_init_ras(struct cxl_port *port)
> @@ -440,6 +462,8 @@ void cxl_endpoint_port_init_ras(struct cxl_port *ep)
> }
>
> cxl_dport_init_ras_reporting(parent_dport, cxlmd->cxlds->dev);
> +
> + cxl_unmask_proto_interrupts(cxlmd->cxlds->dev);
> }
> EXPORT_SYMBOL_NS_GPL(cxl_endpoint_port_init_ras, "CXL");
>
^ permalink raw reply [flat|nested] 92+ messages in thread* Re: [PATCH v12 24/25] CXL/PCI: Enable CXL protocol errors during CXL Port probe
2025-09-25 22:34 ` [PATCH v12 24/25] CXL/PCI: Enable CXL protocol errors during CXL Port probe Terry Bowman
2025-09-30 0:28 ` Dave Jiang
@ 2025-10-03 20:12 ` Cheatham, Benjamin
1 sibling, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:12 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> CXL protocol errors are not enabled for all CXL devices after boot. These
> must be enabled inorder to process CXL protocol errors.
>
> Introduce cxl_unmask_proto_interrupts() to call pci_aer_unmask_internal_errors().
> pci_aer_unmask_internal_errors() expects the pdev->aer_cap is initialized.
> But, dev->aer_cap is not initialized for CXL Upstream Switch Ports and CXL
> Downstream Switch Ports. Initialize the dev->aer_cap if necessary. Enable AER
> correctable internal errors and uncorrectable internal errors for all CXL
> devices.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> ---
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
^ permalink raw reply [flat|nested] 92+ messages in thread
* [PATCH v12 25/25] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup
2025-09-25 22:34 [PATCH v12 00/25] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
` (23 preceding siblings ...)
2025-09-25 22:34 ` [PATCH v12 24/25] CXL/PCI: Enable CXL protocol errors during CXL Port probe Terry Bowman
@ 2025-09-25 22:34 ` Terry Bowman
2025-10-03 20:12 ` Cheatham, Benjamin
24 siblings, 1 reply; 92+ messages in thread
From: Terry Bowman @ 2025-09-25 22:34 UTC (permalink / raw)
To: dave, jonathan.cameron, dave.jiang, alison.schofield,
dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, linux-cxl, alucerop, ira.weiny
Cc: linux-kernel, linux-pci, terry.bowman
During CXL device cleanup the CXL PCIe Port device interrupts remain
enabled. This potentially allows unnecessary interrupt processing on
behalf of the CXL errors while the device is destroyed.
Disable CXL protocol errors by setting the CXL devices' AER mask register.
Introduce pci_aer_mask_internal_errors() similar to pci_aer_unmask_internal_errors().
Add to the AER service driver allowing other subsystems to use.
Introduce cxl_mask_proto_interrupts() to call pci_aer_mask_internal_errors().
Add calls to cxl_mask_proto_interrupts() within CXL Port teardown for CXL
Root Ports, CXL Downstream Switch Ports, CXL Upstream Switch Ports, and CXL
Endpoints. Follow the same "bottom-up" approach used during CXL Port
teardown.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
Changes in v11->v12:
- Keep pci_aer_mask_internal_errors() in driver/pci/pcie/aer.c (Lukas)
- Update commit description for pci_aer_mask_internal_errors()
- Add check `if (port->parent_dport)` in delete_switch_port() (Terry)
Changes in v10->v11:
- Removed guard() cxl_mask_proto_interrupts(). RP was blocking during
testing. (Terry)
---
drivers/cxl/core/core.h | 2 ++
drivers/cxl/core/port.c | 10 +++++++++-
drivers/cxl/core/ras.c | 7 +++++++
drivers/pci/pcie/aer.c | 21 +++++++++++++++++++++
include/linux/aer.h | 2 ++
5 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 3197a71bf7b8..db318a81034a 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -158,6 +158,7 @@ void cxl_cor_error_detected(struct device *dev);
pci_ers_result_t cxl_error_detected(struct device *dev);
void cxl_port_cor_error_detected(struct device *dev);
pci_ers_result_t cxl_port_error_detected(struct device *dev);
+void cxl_mask_proto_interrupts(struct device *dev);
#else
static inline int cxl_ras_init(void)
{
@@ -187,6 +188,7 @@ static inline pci_ers_result_t cxl_port_error_detected(struct device *dev)
{
return PCI_ERS_RESULT_NONE;
}
+static inline void cxl_mask_proto_interrupts(struct device *dev) { }
#endif // CONFIG_CXL_RAS
int cxl_gpf_port_setup(struct cxl_dport *dport);
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index f34a44abb2c9..337a165e8dcd 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -1434,6 +1434,10 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, "CXL");
*/
static void delete_switch_port(struct cxl_port *port)
{
+ cxl_mask_proto_interrupts(port->uport_dev);
+ if (port->parent_dport)
+ cxl_mask_proto_interrupts(port->parent_dport->dport_dev);
+
devm_release_action(port->dev.parent, cxl_unlink_parent_dport, port);
devm_release_action(port->dev.parent, cxl_unlink_uport, port);
devm_release_action(port->dev.parent, unregister_port, port);
@@ -1455,8 +1459,10 @@ static void del_dports(struct cxl_port *port)
device_lock_assert(&port->dev);
- xa_for_each(&port->dports, index, dport)
+ xa_for_each(&port->dports, index, dport) {
+ cxl_mask_proto_interrupts(dport->dport_dev);
del_dport(dport);
+ }
}
struct detach_ctx {
@@ -1483,6 +1489,8 @@ static void cxl_detach_ep(void *data)
{
struct cxl_memdev *cxlmd = data;
+ cxl_mask_proto_interrupts(cxlmd->cxlds->dev);
+
for (int i = cxlmd->depth - 1; i >= 1; i--) {
struct cxl_port *port, *parent_port;
struct detach_ctx ctx = {
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index ea65001daba1..a297ce5e3d97 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -253,6 +253,13 @@ static void cxl_unmask_proto_interrupts(struct device *dev)
pci_aer_unmask_internal_errors(pdev);
}
+void cxl_mask_proto_interrupts(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ pci_aer_mask_internal_errors(pdev);
+}
+
static void cxl_dport_map_ras(struct cxl_dport *dport)
{
struct cxl_register_map *map = &dport->reg_map;
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index e018531f5982..538e953c49cb 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -1119,6 +1119,27 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(pci_aer_unmask_internal_errors);
+/**
+ * pci_aer_mask_internal_errors - mask internal errors
+ * @dev: pointer to the pcie_dev data structure
+ *
+ * Masks internal errors in the Uncorrectable and Correctable Error
+ * Mask registers.
+ *
+ * Note: AER must be enabled and supported by the device which must be
+ * checked in advance, e.g. with pcie_aer_is_native().
+ */
+void pci_aer_mask_internal_errors(struct pci_dev *dev)
+{
+ int aer = dev->aer_cap;
+
+ pci_clear_and_set_config_dword(dev, aer + PCI_ERR_UNCOR_MASK,
+ 0, PCI_ERR_UNC_INTN);
+ pci_clear_and_set_config_dword(dev, aer + PCI_ERR_COR_MASK,
+ 0, PCI_ERR_COR_INTERNAL);
+}
+EXPORT_SYMBOL_GPL(pci_aer_mask_internal_errors);
+
/**
* pci_aer_handle_error - handle logging error into an event log
* @dev: pointer to pci_dev data structure of error source device
diff --git a/include/linux/aer.h b/include/linux/aer.h
index 64aef69fb546..2b89bd940ac1 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -69,6 +69,7 @@ int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
void pci_aer_clear_fatal_status(struct pci_dev *dev);
int pcie_aer_is_native(struct pci_dev *dev);
void pci_aer_unmask_internal_errors(struct pci_dev *dev);
+void pci_aer_mask_internal_errors(struct pci_dev *dev);
#else
static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
{
@@ -77,6 +78,7 @@ static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
+static inline void pci_aer_mask_internal_errors(struct pci_dev *dev) { }
#endif
#ifdef CONFIG_CXL_RAS
--
2.34.1
^ permalink raw reply related [flat|nested] 92+ messages in thread* Re: [PATCH v12 25/25] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup
2025-09-25 22:34 ` [PATCH v12 25/25] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup Terry Bowman
@ 2025-10-03 20:12 ` Cheatham, Benjamin
0 siblings, 0 replies; 92+ messages in thread
From: Cheatham, Benjamin @ 2025-10-03 20:12 UTC (permalink / raw)
To: Terry Bowman
Cc: linux-kernel, linux-pci, dave, jonathan.cameron, dave.jiang,
alison.schofield, dan.j.williams, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, sathyanarayanan.kuppuswamy,
linux-cxl, alucerop, ira.weiny
On 9/25/2025 5:34 PM, Terry Bowman wrote:
> During CXL device cleanup the CXL PCIe Port device interrupts remain
> enabled. This potentially allows unnecessary interrupt processing on
> behalf of the CXL errors while the device is destroyed.
>
> Disable CXL protocol errors by setting the CXL devices' AER mask register.
>
> Introduce pci_aer_mask_internal_errors() similar to pci_aer_unmask_internal_errors().
> Add to the AER service driver allowing other subsystems to use.
>
> Introduce cxl_mask_proto_interrupts() to call pci_aer_mask_internal_errors().
> Add calls to cxl_mask_proto_interrupts() within CXL Port teardown for CXL
> Root Ports, CXL Downstream Switch Ports, CXL Upstream Switch Ports, and CXL
> Endpoints. Follow the same "bottom-up" approach used during CXL Port
> teardown.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
>
> ---
>
> Changes in v11->v12:
> - Keep pci_aer_mask_internal_errors() in driver/pci/pcie/aer.c (Lukas)
> - Update commit description for pci_aer_mask_internal_errors()
> - Add check `if (port->parent_dport)` in delete_switch_port() (Terry)
>
> Changes in v10->v11:
> - Removed guard() cxl_mask_proto_interrupts(). RP was blocking during
> testing. (Terry)
> ---
> drivers/cxl/core/core.h | 2 ++
> drivers/cxl/core/port.c | 10 +++++++++-
> drivers/cxl/core/ras.c | 7 +++++++
> drivers/pci/pcie/aer.c | 21 +++++++++++++++++++++
> include/linux/aer.h | 2 ++
> 5 files changed, 41 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
> index 3197a71bf7b8..db318a81034a 100644
> --- a/drivers/cxl/core/core.h
> +++ b/drivers/cxl/core/core.h
> @@ -158,6 +158,7 @@ void cxl_cor_error_detected(struct device *dev);
> pci_ers_result_t cxl_error_detected(struct device *dev);
> void cxl_port_cor_error_detected(struct device *dev);
> pci_ers_result_t cxl_port_error_detected(struct device *dev);
> +void cxl_mask_proto_interrupts(struct device *dev);
> #else
> static inline int cxl_ras_init(void)
> {
> @@ -187,6 +188,7 @@ static inline pci_ers_result_t cxl_port_error_detected(struct device *dev)
> {
> return PCI_ERS_RESULT_NONE;
> }
> +static inline void cxl_mask_proto_interrupts(struct device *dev) { }
> #endif // CONFIG_CXL_RAS
>
> int cxl_gpf_port_setup(struct cxl_dport *dport);
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index f34a44abb2c9..337a165e8dcd 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -1434,6 +1434,10 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, "CXL");
> */
> static void delete_switch_port(struct cxl_port *port)
> {
> + cxl_mask_proto_interrupts(port->uport_dev);
> + if (port->parent_dport)
> + cxl_mask_proto_interrupts(port->parent_dport->dport_dev);
> +
> devm_release_action(port->dev.parent, cxl_unlink_parent_dport, port);
> devm_release_action(port->dev.parent, cxl_unlink_uport, port);
> devm_release_action(port->dev.parent, unregister_port, port);
> @@ -1455,8 +1459,10 @@ static void del_dports(struct cxl_port *port)
>
> device_lock_assert(&port->dev);
>
> - xa_for_each(&port->dports, index, dport)
> + xa_for_each(&port->dports, index, dport) {
> + cxl_mask_proto_interrupts(dport->dport_dev);
Should this call get moved into del_dport()? I think the dports can get
deleted as the downstream devices leave, which would skip masking the protocol interrupts
on said dports.
If that's not the case, then:
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
> del_dport(dport);
> + }
^ permalink raw reply [flat|nested] 92+ messages in thread