]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cxl/pci: Move CXL driver's RCH error handling into core/ras_rch.c
authorTerry Bowman <terry.bowman@amd.com>
Wed, 14 Jan 2026 18:20:29 +0000 (12:20 -0600)
committerDave Jiang <dave.jiang@intel.com>
Thu, 22 Jan 2026 22:07:04 +0000 (15:07 -0700)
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>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20260114182055.46029-9-terry.bowman@amd.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
drivers/cxl/core/Makefile
drivers/cxl/core/core.h
drivers/cxl/core/pci.c
drivers/cxl/core/ras_rch.c [new file with mode: 0644]
tools/testing/cxl/Kbuild

index b2930cc54f8ba2a3082a0e439031a04977a04c12..b37f38d502d8c344fa6b412c4973d22242b76ce0 100644 (file)
@@ -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_RAS) += ras_rch.o
index bc818de87ccccf18ae5e9dda084451fa74702d36..724361195057eaa27f0559ddc025c1d848c40008 100644 (file)
@@ -149,6 +149,9 @@ int cxl_ras_init(void);
 void cxl_ras_exit(void);
 bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
 void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
+void cxl_dport_map_rch_aer(struct cxl_dport *dport);
+void cxl_disable_rch_root_ints(struct cxl_dport *dport);
+void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds);
 #else
 static inline int cxl_ras_init(void)
 {
@@ -164,14 +167,6 @@ static inline bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras
        return false;
 }
 static inline void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base) { }
-#endif /* CONFIG_CXL_RAS */
-
-/* Restricted CXL Host specific RAS functions */
-#ifdef CONFIG_CXL_RAS
-void cxl_dport_map_rch_aer(struct cxl_dport *dport);
-void cxl_disable_rch_root_ints(struct cxl_dport *dport);
-void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds);
-#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) { }
index e132fff809792eccd71564a3a1827f6421c584bb..b838c59d7a3c0eaa927f778a54fa336730d05309 100644 (file)
@@ -632,121 +632,6 @@ err:
 }
 EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
 
-#ifdef CONFIG_CXL_RAS
-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));
-       }
-}
-
-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);
-}
-
-/*
- * 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;
-}
-
-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);
-}
-#endif
-
 static int cxl_flit_size(struct pci_dev *pdev)
 {
        if (cxl_pci_flit_256(pdev))
diff --git a/drivers/cxl/core/ras_rch.c b/drivers/cxl/core/ras_rch.c
new file mode 100644 (file)
index 0000000..ed58afd
--- /dev/null
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2025 AMD Corporation. All rights reserved. */
+
+#include <linux/types.h>
+#include <linux/aer.h>
+#include "cxl.h"
+#include "core.h"
+#include "cxlmem.h"
+
+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));
+       }
+}
+
+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);
+}
+
+/*
+ * 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;
+}
+
+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);
+}
index b7ea66382f3b1bfbb00b0d988eb96876c4f60a60..6eceefefb0e0449b3aae1d19054faba6489c8b01 100644 (file)
@@ -63,6 +63,7 @@ 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-$(CONFIG_CXL_RAS) += $(CXL_CORE_SRC)/ras_rch.o
 cxl_core-y += config_check.o
 cxl_core-y += cxl_core_test.o
 cxl_core-y += cxl_core_exports.o