Skip to content

Commit fb52bf6

Browse files
author
Fox Snowpatch
committed
1 parent 85ff933 commit fb52bf6

File tree

8 files changed

+159
-40
lines changed

8 files changed

+159
-40
lines changed

drivers/acpi/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,8 @@ config ACPI_EXTLOG
494494
tristate "Extended Error Log support"
495495
depends on X86_MCE && X86_LOCAL_APIC && EDAC
496496
select UEFI_CPER
497+
select ACPI_APEI
498+
select ACPI_APEI_GHES
497499
help
498500
Certain usages such as Predictive Failure Analysis (PFA) require
499501
more information about the error than what can be described in

drivers/acpi/acpi_extlog.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/ratelimit.h>
1313
#include <linux/edac.h>
1414
#include <linux/ras.h>
15+
#include <cxl/event.h>
1516
#include <acpi/ghes.h>
1617
#include <asm/cpu.h>
1718
#include <asm/mce.h>
@@ -132,6 +133,53 @@ static int print_extlog_rcd(const char *pfx,
132133
return 1;
133134
}
134135

136+
static void extlog_print_pcie(struct cper_sec_pcie *pcie_err,
137+
int severity)
138+
{
139+
#ifdef ACPI_APEI_PCIEAER
140+
struct aer_capability_regs *aer;
141+
struct pci_dev *pdev;
142+
unsigned int devfn;
143+
unsigned int bus;
144+
int aer_severity;
145+
int domain;
146+
147+
if (!(pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
148+
pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO))
149+
return;
150+
151+
aer_severity = cper_severity_to_aer(severity);
152+
aer = (struct aer_capability_regs *)pcie_err->aer_info;
153+
domain = pcie_err->device_id.segment;
154+
bus = pcie_err->device_id.bus;
155+
devfn = PCI_DEVFN(pcie_err->device_id.device,
156+
pcie_err->device_id.function);
157+
pdev = pci_get_domain_bus_and_slot(domain, bus, devfn);
158+
if (!pdev)
159+
return;
160+
161+
pci_print_aer(pdev, aer_severity, aer);
162+
pci_dev_put(pdev);
163+
#endif
164+
}
165+
166+
static void
167+
extlog_cxl_cper_handle_prot_err(struct cxl_cper_sec_prot_err *prot_err,
168+
int severity)
169+
{
170+
#ifdef ACPI_APEI_PCIEAER
171+
struct cxl_cper_prot_err_work_data wd;
172+
173+
if (cxl_cper_sec_prot_err_valid(prot_err))
174+
return;
175+
176+
if (cxl_cper_setup_prot_err_work_data(&wd, prot_err, severity))
177+
return;
178+
179+
cxl_cper_handle_prot_err(&wd);
180+
#endif
181+
}
182+
135183
static int extlog_print(struct notifier_block *nb, unsigned long val,
136184
void *data)
137185
{
@@ -183,6 +231,22 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
183231
if (gdata->error_data_length >= sizeof(*mem))
184232
trace_extlog_mem_event(mem, err_seq, fru_id, fru_text,
185233
(u8)gdata->error_severity);
234+
} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
235+
struct cxl_cper_sec_prot_err *prot_err =
236+
acpi_hest_get_payload(gdata);
237+
238+
extlog_cxl_cper_handle_prot_err(prot_err,
239+
gdata->error_severity);
240+
} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
241+
struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata);
242+
243+
extlog_print_pcie(pcie_err, gdata->error_severity);
244+
} else {
245+
void *err = acpi_hest_get_payload(gdata);
246+
247+
log_non_standard_event(sec_type, fru_id, fru_text,
248+
gdata->error_severity, err,
249+
gdata->error_data_length);
186250
}
187251
}
188252

drivers/acpi/apei/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0
22
obj-$(CONFIG_ACPI_APEI) += apei.o
33
obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o
4+
obj-$(CONFIG_ACPI_APEI_PCIEAER) += ghes_helpers.o
45
obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o
56
einj-y := einj-core.o
67
einj-$(CONFIG_ACPI_APEI_EINJ_CXL) += einj-cxl.o

drivers/acpi/apei/ghes.c

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -713,53 +713,17 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
713713
{
714714
#ifdef CONFIG_ACPI_APEI_PCIEAER
715715
struct cxl_cper_prot_err_work_data wd;
716-
u8 *dvsec_start, *cap_start;
717716

718-
if (!(prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS)) {
719-
pr_err_ratelimited("CXL CPER invalid agent type\n");
717+
if (cxl_cper_sec_prot_err_valid(prot_err))
720718
return;
721-
}
722-
723-
if (!(prot_err->valid_bits & PROT_ERR_VALID_ERROR_LOG)) {
724-
pr_err_ratelimited("CXL CPER invalid protocol error log\n");
725-
return;
726-
}
727-
728-
if (prot_err->err_len != sizeof(struct cxl_ras_capability_regs)) {
729-
pr_err_ratelimited("CXL CPER invalid RAS Cap size (%u)\n",
730-
prot_err->err_len);
731-
return;
732-
}
733-
734-
if (!(prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER))
735-
pr_warn(FW_WARN "CXL CPER no device serial number\n");
736719

737720
guard(spinlock_irqsave)(&cxl_cper_prot_err_work_lock);
738721

739722
if (!cxl_cper_prot_err_work)
740723
return;
741724

742-
switch (prot_err->agent_type) {
743-
case RCD:
744-
case DEVICE:
745-
case LD:
746-
case FMLD:
747-
case RP:
748-
case DSP:
749-
case USP:
750-
memcpy(&wd.prot_err, prot_err, sizeof(wd.prot_err));
751-
752-
dvsec_start = (u8 *)(prot_err + 1);
753-
cap_start = dvsec_start + prot_err->dvsec_len;
754-
755-
memcpy(&wd.ras_cap, cap_start, sizeof(wd.ras_cap));
756-
wd.severity = cper_severity_to_aer(severity);
757-
break;
758-
default:
759-
pr_err_ratelimited("CXL CPER invalid agent type: %d\n",
760-
prot_err->agent_type);
725+
if (cxl_cper_setup_prot_err_work_data(&wd, prot_err, severity))
761726
return;
762-
}
763727

764728
if (!kfifo_put(&cxl_cper_prot_err_fifo, wd)) {
765729
pr_err_ratelimited("CXL CPER kfifo overflow\n");

drivers/acpi/apei/ghes_helpers.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
// Copyright(c) 2025 Intel Corporation. All rights reserved
3+
4+
#include <linux/aer.h>
5+
#include <cxl/event.h>
6+
7+
int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err)
8+
{
9+
if (!(prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS)) {
10+
pr_err_ratelimited("CXL CPER invalid agent type\n");
11+
return -EINVAL;
12+
}
13+
14+
if (!(prot_err->valid_bits & PROT_ERR_VALID_ERROR_LOG)) {
15+
pr_err_ratelimited("CXL CPER invalid protocol error log\n");
16+
return -EINVAL;
17+
}
18+
19+
if (prot_err->err_len != sizeof(struct cxl_ras_capability_regs)) {
20+
pr_err_ratelimited("CXL CPER invalid RAS Cap size (%u)\n",
21+
prot_err->err_len);
22+
return -EINVAL;
23+
}
24+
25+
if ((prot_err->agent_type == RCD || prot_err->agent_type == DEVICE ||
26+
prot_err->agent_type == LD || prot_err->agent_type == FMLD) &&
27+
!(prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER))
28+
pr_warn_ratelimited(FW_WARN
29+
"CXL CPER no device serial number\n");
30+
31+
return 0;
32+
}
33+
EXPORT_SYMBOL_GPL(cxl_cper_sec_prot_err_valid);
34+
35+
int cxl_cper_setup_prot_err_work_data(struct cxl_cper_prot_err_work_data *wd,
36+
struct cxl_cper_sec_prot_err *prot_err,
37+
int severity)
38+
{
39+
u8 *dvsec_start, *cap_start;
40+
41+
switch (prot_err->agent_type) {
42+
case RCD:
43+
case DEVICE:
44+
case LD:
45+
case FMLD:
46+
case RP:
47+
case DSP:
48+
case USP:
49+
memcpy(&wd->prot_err, prot_err, sizeof(wd->prot_err));
50+
51+
dvsec_start = (u8 *)(prot_err + 1);
52+
cap_start = dvsec_start + prot_err->dvsec_len;
53+
54+
memcpy(&wd->ras_cap, cap_start, sizeof(wd->ras_cap));
55+
wd->severity = cper_severity_to_aer(severity);
56+
break;
57+
default:
58+
pr_err_ratelimited("CXL CPER invalid agent type: %d\n",
59+
prot_err->agent_type);
60+
return -EINVAL;
61+
}
62+
63+
return 0;
64+
}
65+
EXPORT_SYMBOL_GPL(cxl_cper_setup_prot_err_work_data);

drivers/cxl/core/ras.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ static int match_memdev_by_parent(struct device *dev, const void *uport)
6363
return 0;
6464
}
6565

66-
static void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
66+
void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
6767
{
6868
unsigned int devfn = PCI_DEVFN(data->prot_err.agent_addr.device,
6969
data->prot_err.agent_addr.function);
@@ -104,6 +104,7 @@ static void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
104104
else
105105
cxl_cper_trace_uncorr_prot_err(cxlmd, data->ras_cap);
106106
}
107+
EXPORT_SYMBOL_GPL(cxl_cper_handle_prot_err);
107108

108109
static void cxl_cper_prot_err_work_fn(struct work_struct *work)
109110
{

drivers/pci/pcie/aer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,7 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
971971
pcie_print_tlp_log(dev, &aer->header_log, info.level,
972972
dev_fmt(" "));
973973
}
974-
EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL");
974+
EXPORT_SYMBOL_GPL(pci_print_aer);
975975

976976
/**
977977
* add_error_device - list device to be handled

include/cxl/event.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,4 +320,26 @@ static inline int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data
320320
}
321321
#endif
322322

323+
#ifdef CONFIG_ACPI_APEI_PCIEAER
324+
int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err);
325+
int cxl_cper_setup_prot_err_work_data(struct cxl_cper_prot_err_work_data *wd,
326+
struct cxl_cper_sec_prot_err *prot_err,
327+
int severity);
328+
#else
329+
static inline int
330+
cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err)
331+
{
332+
return -EOPNOTSUPP;
333+
}
334+
static inline int
335+
cxl_cper_setup_prot_err_work_data(struct cxl_cper_prot_err_work_data *wd,
336+
struct cxl_cper_sec_prot_err *prot_err,
337+
int severity)
338+
{
339+
return -EOPNOTSUPP;
340+
}
341+
#endif
342+
343+
void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *wd);
344+
323345
#endif /* _LINUX_CXL_EVENT_H */

0 commit comments

Comments
 (0)