@@ -188,11 +188,11 @@ static inline struct device *dport_to_host(struct cxl_dport *dport)
void cxl_ras_init(void);
void cxl_ras_exit(void);
bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport,
- void __iomem *ras_base);
+ void __iomem *ras_base, u64 serial);
void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port,
struct cxl_dport *dport);
void cxl_handle_cor_ras(struct cxl_port *port, struct cxl_dport *dport,
- void __iomem *ras_base);
+ void __iomem *ras_base, u64 serial);
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 pci_dev *pdev);
@@ -202,14 +202,14 @@ void devm_cxl_dport_ras_setup(struct cxl_dport *dport);
static inline void cxl_ras_init(void) { }
static inline void cxl_ras_exit(void) { }
static inline bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport,
- void __iomem *ras_base)
+ void __iomem *ras_base, u64 serial)
{
return false;
}
static inline void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port,
struct cxl_dport *dport) { }
static inline void cxl_handle_cor_ras(struct cxl_port *port, struct cxl_dport *dport,
- void __iomem *ras_base) { }
+ void __iomem *ras_base, u64 serial) { }
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 pci_dev *pdev) { }
@@ -12,69 +12,37 @@
static_assert(CXL_HEADERLOG_TRACE_SIZE_U32 == 128,
"rasdaemon ABI requires exactly 128 u32s");
-static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
- struct cxl_ras_capability_regs ras_cap)
-{
- u32 status = ras_cap.cor_status & ~ras_cap.cor_mask;
-
- trace_cxl_port_aer_correctable_error(&pdev->dev, status);
-}
-
-static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
- struct cxl_ras_capability_regs ras_cap)
-{
- u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {};
- u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask;
- u32 fe;
-
- if (hweight32(status) > 1)
- fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK,
- ras_cap.cap_control));
- else
- fe = status;
-
- memcpy(hl, ras_cap.header_log, CXL_HEADERLOG_SIZE);
- trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe, hl);
-}
-
-static void cxl_cper_trace_corr_prot_err(struct cxl_memdev *cxlmd,
- struct cxl_ras_capability_regs ras_cap)
-{
- u32 status = ras_cap.cor_status & ~ras_cap.cor_mask;
-
- trace_cxl_aer_correctable_error(cxlmd, status);
-}
-
-static void
-cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd,
- struct cxl_ras_capability_regs ras_cap)
+static void cxl_cper_trace_uncorr_prot_err(struct cxl_port *port, struct cxl_dport *dport,
+ u64 serial, struct cxl_ras_capability_regs *ras_cap)
{
u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {};
- u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask;
+ u32 status = ras_cap->uncor_status & ~ras_cap->uncor_mask;
u32 fe;
if (hweight32(status) > 1)
fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK,
- ras_cap.cap_control));
+ ras_cap->cap_control));
else
fe = status;
/*
- * ras_cap.header_log[] holds CXL_HEADERLOG_SIZE_U32 (16) hardware
+ * ras_cap->header_log[] holds CXL_HEADERLOG_SIZE_U32 (16) hardware
* dwords. Copy them into the front of a zero-filled
* CXL_HEADERLOG_TRACE_SIZE_U32 (128) u32 staging buffer so the trace
* event memcpy sees a full 512-byte source and the userspace ABI
* (rasdaemon) is preserved.
*/
- memcpy(hl, ras_cap.header_log, CXL_HEADERLOG_SIZE);
- trace_cxl_aer_uncorrectable_error(cxlmd, status, fe, hl);
+ memcpy(hl, ras_cap->header_log, CXL_HEADERLOG_SIZE);
+ trace_cxl_aer_uncorrectable_error(port, dport, status, fe,
+ hl, serial);
}
-static int match_memdev_by_parent(struct device *dev, const void *uport)
+static void cxl_cper_trace_corr_prot_err(struct cxl_port *port, struct cxl_dport *dport,
+ u64 serial, struct cxl_ras_capability_regs *ras_cap)
{
- if (is_cxl_memdev(dev) && dev->parent == uport)
- return 1;
- return 0;
+ u32 status = ras_cap->cor_status & ~ras_cap->cor_mask;
+
+ trace_cxl_aer_correctable_error(port, dport, status, serial);
}
/**
@@ -108,44 +76,42 @@ static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dpor
void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
{
+ struct cxl_dport *dport;
+ struct device *host;
unsigned int devfn = PCI_DEVFN(data->prot_err.agent_addr.device,
data->prot_err.agent_addr.function);
- struct pci_dev *pdev __free(pci_dev_put) =
- pci_get_domain_bus_and_slot(data->prot_err.agent_addr.segment,
- data->prot_err.agent_addr.bus,
- devfn);
- struct cxl_memdev *cxlmd;
- int port_type;
-
- if (!pdev)
+ struct pci_dev *pdev __free(pci_dev_put) = pci_get_domain_bus_and_slot(
+ data->prot_err.agent_addr.segment, data->prot_err.agent_addr.bus, devfn);
+ if (!pdev) {
+ pr_err_ratelimited("Failed to find CPER device in CXL topology\n");
return;
+ }
- port_type = pci_pcie_type(pdev);
- if (port_type == PCI_EXP_TYPE_ROOT_PORT ||
- port_type == PCI_EXP_TYPE_DOWNSTREAM ||
- port_type == PCI_EXP_TYPE_UPSTREAM) {
- if (data->severity == AER_CORRECTABLE)
- cxl_cper_trace_corr_port_prot_err(pdev, data->ras_cap);
- else
- cxl_cper_trace_uncorr_port_prot_err(pdev, data->ras_cap);
-
+ struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_dev(&pdev->dev, NULL);
+ if (!port) {
+ dev_err_ratelimited(&pdev->dev,
+ "Failed to find parent port device in CXL topology\n");
return;
}
- guard(device)(&pdev->dev);
- if (!pdev->dev.driver)
- return;
+ host = is_cxl_root(port) ? port->uport_dev : &port->dev;
- struct device *mem_dev __free(put_device) = bus_find_device(
- &cxl_bus_type, NULL, pdev, match_memdev_by_parent);
- if (!mem_dev)
- return;
+ /*
+ * Lock host to serialize the dport lookup/trace against dport teardown.
+ * Don't gate on host->driver as the CPER record is FW provided and needs
+ * no device MMIO.
+ */
+ guard(device)(host);
+
+ /* dport is NULL for Endpoint and Upstream Port devices */
+ dport = cxl_find_dport_by_dev(port, &pdev->dev);
- cxlmd = to_cxl_memdev(mem_dev);
if (data->severity == AER_CORRECTABLE)
- cxl_cper_trace_corr_prot_err(cxlmd, data->ras_cap);
+ cxl_cper_trace_corr_prot_err(port, dport, pdev->dsn,
+ &data->ras_cap);
else
- cxl_cper_trace_uncorr_prot_err(cxlmd, data->ras_cap);
+ cxl_cper_trace_uncorr_prot_err(port, dport, pdev->dsn,
+ &data->ras_cap);
}
EXPORT_SYMBOL_GPL(cxl_cper_handle_prot_err);
@@ -232,14 +198,15 @@ void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dpo
if (!ras_base)
panic("CXL: UCE with unmapped RAS registers");
- if (cxl_handle_ras(port, dport, ras_base))
+ if (cxl_handle_ras(port, dport, ras_base, pdev->dsn))
panic("CXL cachemem error");
dev_dbg(&pdev->dev,
"CXL UCE signaled but no CXL RAS status bits set\n");
}
-void cxl_handle_cor_ras(struct cxl_port *port, struct cxl_dport *dport, void __iomem *ras_base)
+void cxl_handle_cor_ras(struct cxl_port *port, struct cxl_dport *dport,
+ void __iomem *ras_base, u64 serial)
{
void __iomem *addr;
u32 status;
@@ -251,12 +218,7 @@ void cxl_handle_cor_ras(struct cxl_port *port, struct cxl_dport *dport, void __i
status = readl(addr);
if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
- if (is_cxl_endpoint(port))
- trace_cxl_aer_correctable_error(to_cxl_memdev(port->uport_dev), status);
- else if (dport)
- trace_cxl_port_aer_correctable_error(dport->dport_dev, status);
- else
- trace_cxl_port_aer_correctable_error(port->uport_dev, status);
+ trace_cxl_aer_correctable_error(port, dport, status, serial);
}
}
@@ -281,7 +243,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.
*/
-bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport, void __iomem *ras_base)
+bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport,
+ void __iomem *ras_base, u64 serial)
{
u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {};
void __iomem *addr;
@@ -308,12 +271,7 @@ bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport, void __iomem
}
header_log_copy(ras_base, hl);
- if (is_cxl_endpoint(port))
- trace_cxl_aer_uncorrectable_error(to_cxl_memdev(port->uport_dev), status, fe, hl);
- else if (dport)
- trace_cxl_port_aer_uncorrectable_error(dport->dport_dev, status, fe, hl);
- else
- trace_cxl_port_aer_uncorrectable_error(port->uport_dev, status, fe, hl);
+ trace_cxl_aer_uncorrectable_error(port, dport, status, fe, hl, serial);
writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
@@ -354,7 +312,8 @@ pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev,
* block cannot attribute the error to CXL and must not panic.
* The switch cases below then handle AER recovery.
*/
- ue = cxl_handle_ras(port, NULL, to_ras_base(port, NULL));
+ ue = cxl_handle_ras(port, NULL, to_ras_base(port, NULL),
+ pdev->dsn);
}
/*
@@ -386,7 +345,7 @@ static void cxl_handle_proto_error(struct pci_dev *pdev, struct cxl_port *port,
struct cxl_dport *dport, int severity)
{
if (severity == AER_CORRECTABLE)
- cxl_handle_cor_ras(port, dport, to_ras_base(port, dport));
+ cxl_handle_cor_ras(port, dport, to_ras_base(port, dport), pdev->dsn);
else
cxl_do_recovery(pdev, port, dport);
}
@@ -123,7 +123,8 @@ void cxl_handle_rdport_errors(struct pci_dev *pdev)
*/
if (aer_regs.cor_status & ~aer_regs.cor_mask) {
pci_print_aer(pdev, AER_CORRECTABLE, &aer_regs);
- cxl_handle_cor_ras(port, dport, to_ras_base(port, dport));
+ cxl_handle_cor_ras(port, dport, to_ras_base(port, dport),
+ pdev->dsn);
}
if (uncor_status) {
@@ -2,7 +2,42 @@
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
#include <cxl.h>
+#include <cxlmem.h>
#include "core.h"
+const char *cxl_trace_memdev_name(struct cxl_port *port)
+{
+ if (is_cxl_endpoint(port)) {
+ struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
+
+ return dev_name(&cxlmd->dev);
+ }
+
+ return "";
+}
+
+const char *cxl_trace_host_name(struct cxl_port *port)
+{
+ if (is_cxl_endpoint(port)) {
+ struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
+
+ return dev_name(cxlmd->dev.parent);
+ }
+
+ return dev_name(port->uport_dev);
+}
+
+const char *cxl_trace_port_name(struct cxl_port *port)
+{
+ return dev_name(&port->dev);
+}
+
+const char *cxl_trace_dport_name(struct cxl_dport *dport)
+{
+ if (dport)
+ return dev_name(dport->dport_dev);
+ return "";
+}
+
#define CREATE_TRACE_POINTS
#include "trace.h"
@@ -48,44 +48,15 @@
{ 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_TRACE_SIZE_U32)
- ),
- TP_fast_assign(
- __assign_str(device);
- __assign_str(host);
- __entry->status = status;
- __entry->first_error = fe;
- /*
- * Embed headerlog data for user app retrieval and parsing,
- * but no need to print in the trace buffer. Only
- * CXL_HEADERLOG_SIZE_U32 (16) dwords are hardware data;
- * the remaining entries preserve the 512-byte ABI layout
- * rasdaemon depends on and are zero-filled by the caller.
- */
- memcpy(__entry->header_log, hl,
- CXL_HEADERLOG_TRACE_SIZE_U32 * sizeof(u32));
- ),
- 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(struct cxl_port *port, struct cxl_dport *dport,
+ u32 status, u32 fe, u32 *hl, u64 serial),
+ TP_ARGS(port, dport, status, fe, hl, serial),
TP_STRUCT__entry(
- __string(memdev, dev_name(&cxlmd->dev))
- __string(host, dev_name(cxlmd->dev.parent))
+ __string(memdev, cxl_trace_memdev_name(port))
+ __string(port, cxl_trace_port_name(port))
+ __string(dport, cxl_trace_dport_name(dport))
+ __string(host, cxl_trace_host_name(port))
__field(u64, serial)
__field(u32, status)
__field(u32, first_error)
@@ -93,8 +64,10 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
),
TP_fast_assign(
__assign_str(memdev);
+ __assign_str(port);
+ __assign_str(dport);
__assign_str(host);
- __entry->serial = cxlmd->cxlds->serial;
+ __entry->serial = serial;
__entry->status = status;
__entry->first_error = fe;
/*
@@ -107,8 +80,9 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
memcpy(__entry->header_log, hl,
CXL_HEADERLOG_TRACE_SIZE_U32 * sizeof(u32));
),
- TP_printk("memdev=%s host=%s serial=%llu: status: '%s' first_error: '%s'",
- __get_str(memdev), __get_str(host), __entry->serial,
+ TP_printk("memdev=%s port=%s dport=%s host=%s serial=%llu: status: '%s' first_error: '%s'",
+ __get_str(memdev), __get_str(port), __get_str(dport),
+ __get_str(host), __entry->serial,
show_uc_errs(__entry->status),
show_uc_errs(__entry->first_error)
)
@@ -132,42 +106,29 @@ 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(struct cxl_port *port, struct cxl_dport *dport,
+ u32 status, u64 serial),
+ TP_ARGS(port, dport, status, serial),
TP_STRUCT__entry(
- __string(memdev, dev_name(&cxlmd->dev))
- __string(host, dev_name(cxlmd->dev.parent))
+ __string(memdev, cxl_trace_memdev_name(port))
+ __string(port, cxl_trace_port_name(port))
+ __string(dport, cxl_trace_dport_name(dport))
+ __string(host, cxl_trace_host_name(port))
__field(u64, serial)
__field(u32, status)
),
TP_fast_assign(
__assign_str(memdev);
+ __assign_str(port);
+ __assign_str(dport);
__assign_str(host);
- __entry->serial = cxlmd->cxlds->serial;
+ __entry->serial = serial;
__entry->status = status;
),
- TP_printk("memdev=%s host=%s serial=%llu: status: '%s'",
- __get_str(memdev), __get_str(host), __entry->serial,
+ TP_printk("memdev=%s port=%s dport=%s host=%s serial=%llu: status: '%s'",
+ __get_str(memdev), __get_str(port), __get_str(dport),
+ __get_str(host), __entry->serial,
show_ce_errs(__entry->status)
)
);
@@ -125,6 +125,13 @@ static inline int cxl_memdev_attach_region(struct cxl_memdev *cxlmd)
#endif
struct cxl_memdev *devm_cxl_add_classdev(struct cxl_dev_state *cxlds);
+
+/* trace-event helpers */
+const char *cxl_trace_memdev_name(struct cxl_port *port);
+const char *cxl_trace_host_name(struct cxl_port *port);
+const char *cxl_trace_port_name(struct cxl_port *port);
+const char *cxl_trace_dport_name(struct cxl_dport *dport);
+
struct cxl_memdev *__devm_cxl_add_memdev(struct cxl_dev_state *cxlds,
const struct cxl_memdev_attach *attach);
int devm_cxl_sanitize_setup_notifier(struct device *host,