This allow us to collect AER events via generic tracing framework
like mce_record event.
Signed-off-by: Hidetoshi Seto <seto.hidetoshi@xxxxxxxxxxxxxx>
---
drivers/pci/pcie/aer/aerdrv_core.c | 10 +++++-
include/trace/events/pcie_aer.h | 68 ++++++++++++++++++++++++++++++++++++
2 files changed, 77 insertions(+), 1 deletions(-)
create mode 100644 include/trace/events/pcie_aer.h
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 09e61ca..8c1de83 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -25,6 +25,9 @@
#include <linux/delay.h>
#include "aerdrv.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/pcie_aer.h>
+
static int forceload;
static int nosourceid;
module_param(forceload, bool, 0);
@@ -652,6 +655,8 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
int pos, temp;
info->status = 0;
+ info->mask = 0;
+ info->first_error = 0;
info->tlp_header_valid = 0;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
@@ -708,8 +713,11 @@ static inline void aer_process_err_devices(struct pcie_device *p_device,
/* Report all before handle them, not to lost records by reset etc. */
for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) {
- if (get_device_error_info(e_info->dev[i], e_info))
+ if (get_device_error_info(e_info->dev[i], e_info)) {
aer_print_error(e_info->dev[i], e_info);
+ /* Emit the trace record */
+ trace_aer_record(e_info->dev[i], e_info);
+ }
}
/*
diff --git a/include/trace/events/pcie_aer.h b/include/trace/events/pcie_aer.h
new file mode 100644
index 0000000..d1d6497
--- /dev/null
+++ b/include/trace/events/pcie_aer.h
@@ -0,0 +1,68 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM pcie_aer
+
+#if !defined(_TRACE_PCIE_AER_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PCIE_AER_H
+
+#include <linux/tracepoint.h>
+
+#define aer_severity_string \
+ { AER_CORRECTABLE, "ERR_COR" }, \
+ { AER_NONFATAL, "ERR_NONFATAL" }, \
+ { AER_FATAL, "ERR_FATAL" }
+
+#define aer_form_header(ent, dw0) \
+do { \
+ char *c = (unsigned char *)dw0; \
+ sprintf(ent, "%02x%02x%02x%02x %02x%02x%02x%02x " \
+ "%02x%02x%02x%02x %02x%02x%02x%02x", \
+ *(c + 3), *(c + 2), *(c + 1), *c, \
+ *(c + 7), *(c + 6), *(c + 5), *(c + 4), \
+ *(c + 11), *(c + 10), *(c + 9), *(c + 8), \
+ *(c + 15), *(c + 14), *(c + 13), *(c + 12)); \
+} while (0)
+
+
+TRACE_EVENT(aer_record,
+
+ TP_PROTO(struct pci_dev *pdev, struct aer_err_info *e_info),
+
+ TP_ARGS(pdev, e_info),
+
+ TP_STRUCT__entry(
+ __field( u32, status )
+ __field( u32, mask )
+ __field( u8, severity )
+ __field( u8, fep )
+ __field( bool, hdr_valid )
+ __string( dstr, dev_driver_string(&pdev->dev) )
+ __string( name, dev_name(&pdev->dev) )
+ __dynamic_array(char, hdr, (e_info->tlp_header_valid ? 40 : 0))
+ ),
+
+ TP_fast_assign(
+ __entry->status = e_info->status;
+ __entry->mask = e_info->mask;
+ __entry->severity = e_info->severity;
+ __entry->fep = e_info->first_error;
+ __entry->hdr_valid = e_info->tlp_header_valid;
+
+ __assign_str(dstr, dev_driver_string(&pdev->dev));
+ __assign_str(name, dev_name(&pdev->dev));
+
+ if (e_info->tlp_header_valid)
+ aer_form_header(__get_str(hdr), &e_info->tlp.dw0);
+ ),
+
+ TP_printk("%s %s: %s status/mask=%08xh/%08xh fep=%d, header=%s",
+ __get_str(dstr), __get_str(name),
+ __print_symbolic(__entry->severity, aer_severity_string),
+ __entry->status, __entry->mask, __entry->fep,
+ __entry->hdr_valid ? __get_str(hdr) : "<not available>"
+ )
+);
+
+#endif /* _TRACE_PCIE_AER_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>