Skip to content

Commit 0ff60f2

Browse files
ktbowmandavejiang
authored andcommitted
cxl/pci: Move CXL driver's RCH error handling into core/ras_rch.c
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>
1 parent d18f1b7 commit 0ff60f2

5 files changed

Lines changed: 126 additions & 123 deletions

File tree

drivers/cxl/core/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ cxl_core-$(CONFIG_CXL_MCE) += mce.o
2020
cxl_core-$(CONFIG_CXL_FEATURES) += features.o
2121
cxl_core-$(CONFIG_CXL_EDAC_MEM_FEATURES) += edac.o
2222
cxl_core-$(CONFIG_CXL_RAS) += ras.o
23+
cxl_core-$(CONFIG_CXL_RAS) += ras_rch.o

drivers/cxl/core/core.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ int cxl_ras_init(void);
149149
void cxl_ras_exit(void);
150150
bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
151151
void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base);
152+
void cxl_dport_map_rch_aer(struct cxl_dport *dport);
153+
void cxl_disable_rch_root_ints(struct cxl_dport *dport);
154+
void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds);
152155
#else
153156
static inline int cxl_ras_init(void)
154157
{
@@ -164,14 +167,6 @@ static inline bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras
164167
return false;
165168
}
166169
static inline void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base) { }
167-
#endif /* CONFIG_CXL_RAS */
168-
169-
/* Restricted CXL Host specific RAS functions */
170-
#ifdef CONFIG_CXL_RAS
171-
void cxl_dport_map_rch_aer(struct cxl_dport *dport);
172-
void cxl_disable_rch_root_ints(struct cxl_dport *dport);
173-
void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds);
174-
#else
175170
static inline void cxl_dport_map_rch_aer(struct cxl_dport *dport) { }
176171
static inline void cxl_disable_rch_root_ints(struct cxl_dport *dport) { }
177172
static inline void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { }

drivers/cxl/core/pci.c

Lines changed: 0 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -632,121 +632,6 @@ void read_cdat_data(struct cxl_port *port)
632632
}
633633
EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
634634

635-
#ifdef CONFIG_CXL_RAS
636-
void cxl_dport_map_rch_aer(struct cxl_dport *dport)
637-
{
638-
resource_size_t aer_phys;
639-
struct device *host;
640-
u16 aer_cap;
641-
642-
aer_cap = cxl_rcrb_to_aer(dport->dport_dev, dport->rcrb.base);
643-
if (aer_cap) {
644-
host = dport->reg_map.host;
645-
aer_phys = aer_cap + dport->rcrb.base;
646-
dport->regs.dport_aer = devm_cxl_iomap_block(host, aer_phys,
647-
sizeof(struct aer_capability_regs));
648-
}
649-
}
650-
651-
void cxl_disable_rch_root_ints(struct cxl_dport *dport)
652-
{
653-
void __iomem *aer_base = dport->regs.dport_aer;
654-
u32 aer_cmd_mask, aer_cmd;
655-
656-
if (!aer_base)
657-
return;
658-
659-
/*
660-
* Disable RCH root port command interrupts.
661-
* CXL 3.0 12.2.1.1 - RCH Downstream Port-detected Errors
662-
*
663-
* This sequence may not be necessary. CXL spec states disabling
664-
* the root cmd register's interrupts is required. But, PCI spec
665-
* shows these are disabled by default on reset.
666-
*/
667-
aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
668-
PCI_ERR_ROOT_CMD_NONFATAL_EN |
669-
PCI_ERR_ROOT_CMD_FATAL_EN);
670-
aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
671-
aer_cmd &= ~aer_cmd_mask;
672-
writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
673-
}
674-
675-
/*
676-
* Copy the AER capability registers using 32 bit read accesses.
677-
* This is necessary because RCRB AER capability is MMIO mapped. Clear the
678-
* status after copying.
679-
*
680-
* @aer_base: base address of AER capability block in RCRB
681-
* @aer_regs: destination for copying AER capability
682-
*/
683-
static bool cxl_rch_get_aer_info(void __iomem *aer_base,
684-
struct aer_capability_regs *aer_regs)
685-
{
686-
int read_cnt = sizeof(struct aer_capability_regs) / sizeof(u32);
687-
u32 *aer_regs_buf = (u32 *)aer_regs;
688-
int n;
689-
690-
if (!aer_base)
691-
return false;
692-
693-
/* Use readl() to guarantee 32-bit accesses */
694-
for (n = 0; n < read_cnt; n++)
695-
aer_regs_buf[n] = readl(aer_base + n * sizeof(u32));
696-
697-
writel(aer_regs->uncor_status, aer_base + PCI_ERR_UNCOR_STATUS);
698-
writel(aer_regs->cor_status, aer_base + PCI_ERR_COR_STATUS);
699-
700-
return true;
701-
}
702-
703-
/* Get AER severity. Return false if there is no error. */
704-
static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,
705-
int *severity)
706-
{
707-
if (aer_regs->uncor_status & ~aer_regs->uncor_mask) {
708-
if (aer_regs->uncor_status & PCI_ERR_ROOT_FATAL_RCV)
709-
*severity = AER_FATAL;
710-
else
711-
*severity = AER_NONFATAL;
712-
return true;
713-
}
714-
715-
if (aer_regs->cor_status & ~aer_regs->cor_mask) {
716-
*severity = AER_CORRECTABLE;
717-
return true;
718-
}
719-
720-
return false;
721-
}
722-
723-
void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
724-
{
725-
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
726-
struct aer_capability_regs aer_regs;
727-
struct cxl_dport *dport;
728-
int severity;
729-
730-
struct cxl_port *port __free(put_cxl_port) =
731-
cxl_pci_find_port(pdev, &dport);
732-
if (!port)
733-
return;
734-
735-
if (!cxl_rch_get_aer_info(dport->regs.dport_aer, &aer_regs))
736-
return;
737-
738-
if (!cxl_rch_get_aer_severity(&aer_regs, &severity))
739-
return;
740-
741-
pci_print_aer(pdev, severity, &aer_regs);
742-
743-
if (severity == AER_CORRECTABLE)
744-
cxl_handle_cor_ras(cxlds, dport->regs.ras);
745-
else
746-
cxl_handle_ras(cxlds, dport->regs.ras);
747-
}
748-
#endif
749-
750635
static int cxl_flit_size(struct pci_dev *pdev)
751636
{
752637
if (cxl_pci_flit_256(pdev))

drivers/cxl/core/ras_rch.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/* Copyright(c) 2025 AMD Corporation. All rights reserved. */
3+
4+
#include <linux/types.h>
5+
#include <linux/aer.h>
6+
#include "cxl.h"
7+
#include "core.h"
8+
#include "cxlmem.h"
9+
10+
void cxl_dport_map_rch_aer(struct cxl_dport *dport)
11+
{
12+
resource_size_t aer_phys;
13+
struct device *host;
14+
u16 aer_cap;
15+
16+
aer_cap = cxl_rcrb_to_aer(dport->dport_dev, dport->rcrb.base);
17+
if (aer_cap) {
18+
host = dport->reg_map.host;
19+
aer_phys = aer_cap + dport->rcrb.base;
20+
dport->regs.dport_aer =
21+
devm_cxl_iomap_block(host, aer_phys,
22+
sizeof(struct aer_capability_regs));
23+
}
24+
}
25+
26+
void cxl_disable_rch_root_ints(struct cxl_dport *dport)
27+
{
28+
void __iomem *aer_base = dport->regs.dport_aer;
29+
u32 aer_cmd_mask, aer_cmd;
30+
31+
if (!aer_base)
32+
return;
33+
34+
/*
35+
* Disable RCH root port command interrupts.
36+
* CXL 3.0 12.2.1.1 - RCH Downstream Port-detected Errors
37+
*
38+
* This sequence may not be necessary. CXL spec states disabling
39+
* the root cmd register's interrupts is required. But, PCI spec
40+
* shows these are disabled by default on reset.
41+
*/
42+
aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
43+
PCI_ERR_ROOT_CMD_NONFATAL_EN |
44+
PCI_ERR_ROOT_CMD_FATAL_EN);
45+
aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
46+
aer_cmd &= ~aer_cmd_mask;
47+
writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
48+
}
49+
50+
/*
51+
* Copy the AER capability registers using 32 bit read accesses.
52+
* This is necessary because RCRB AER capability is MMIO mapped. Clear the
53+
* status after copying.
54+
*
55+
* @aer_base: base address of AER capability block in RCRB
56+
* @aer_regs: destination for copying AER capability
57+
*/
58+
static bool cxl_rch_get_aer_info(void __iomem *aer_base,
59+
struct aer_capability_regs *aer_regs)
60+
{
61+
int read_cnt = sizeof(struct aer_capability_regs) / sizeof(u32);
62+
u32 *aer_regs_buf = (u32 *)aer_regs;
63+
int n;
64+
65+
if (!aer_base)
66+
return false;
67+
68+
/* Use readl() to guarantee 32-bit accesses */
69+
for (n = 0; n < read_cnt; n++)
70+
aer_regs_buf[n] = readl(aer_base + n * sizeof(u32));
71+
72+
writel(aer_regs->uncor_status, aer_base + PCI_ERR_UNCOR_STATUS);
73+
writel(aer_regs->cor_status, aer_base + PCI_ERR_COR_STATUS);
74+
75+
return true;
76+
}
77+
78+
/* Get AER severity. Return false if there is no error. */
79+
static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,
80+
int *severity)
81+
{
82+
if (aer_regs->uncor_status & ~aer_regs->uncor_mask) {
83+
if (aer_regs->uncor_status & PCI_ERR_ROOT_FATAL_RCV)
84+
*severity = AER_FATAL;
85+
else
86+
*severity = AER_NONFATAL;
87+
return true;
88+
}
89+
90+
if (aer_regs->cor_status & ~aer_regs->cor_mask) {
91+
*severity = AER_CORRECTABLE;
92+
return true;
93+
}
94+
95+
return false;
96+
}
97+
98+
void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
99+
{
100+
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
101+
struct aer_capability_regs aer_regs;
102+
struct cxl_dport *dport;
103+
int severity;
104+
105+
struct cxl_port *port __free(put_cxl_port) =
106+
cxl_pci_find_port(pdev, &dport);
107+
if (!port)
108+
return;
109+
110+
if (!cxl_rch_get_aer_info(dport->regs.dport_aer, &aer_regs))
111+
return;
112+
113+
if (!cxl_rch_get_aer_severity(&aer_regs, &severity))
114+
return;
115+
116+
pci_print_aer(pdev, severity, &aer_regs);
117+
if (severity == AER_CORRECTABLE)
118+
cxl_handle_cor_ras(cxlds, dport->regs.ras);
119+
else
120+
cxl_handle_ras(cxlds, dport->regs.ras);
121+
}

tools/testing/cxl/Kbuild

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ cxl_core-$(CONFIG_CXL_MCE) += $(CXL_CORE_SRC)/mce.o
6363
cxl_core-$(CONFIG_CXL_FEATURES) += $(CXL_CORE_SRC)/features.o
6464
cxl_core-$(CONFIG_CXL_EDAC_MEM_FEATURES) += $(CXL_CORE_SRC)/edac.o
6565
cxl_core-$(CONFIG_CXL_RAS) += $(CXL_CORE_SRC)/ras.o
66+
cxl_core-$(CONFIG_CXL_RAS) += $(CXL_CORE_SRC)/ras_rch.o
6667
cxl_core-y += config_check.o
6768
cxl_core-y += cxl_core_test.o
6869
cxl_core-y += cxl_core_exports.o

0 commit comments

Comments
 (0)