|
@@ -19,6 +19,7 @@
|
|
|
#include <linux/errno.h>
|
|
|
#include <linux/pm.h>
|
|
|
#include <linux/suspend.h>
|
|
|
+#include <linux/cper.h>
|
|
|
|
|
|
#include "aerdrv.h"
|
|
|
|
|
@@ -201,3 +202,61 @@ void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
|
|
|
info->multi_error_valid ? "Multiple " : "",
|
|
|
aer_error_severity_string[info->severity], info->id);
|
|
|
}
|
|
|
+
|
|
|
+#ifdef CONFIG_ACPI_APEI_PCIEAER
|
|
|
+static int cper_severity_to_aer(int cper_severity)
|
|
|
+{
|
|
|
+ switch (cper_severity) {
|
|
|
+ case CPER_SEV_RECOVERABLE:
|
|
|
+ return AER_NONFATAL;
|
|
|
+ case CPER_SEV_FATAL:
|
|
|
+ return AER_FATAL;
|
|
|
+ default:
|
|
|
+ return AER_CORRECTABLE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void cper_print_aer(const char *prefix, int cper_severity,
|
|
|
+ struct aer_capability_regs *aer)
|
|
|
+{
|
|
|
+ int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0;
|
|
|
+ u32 status, mask;
|
|
|
+ const char **status_strs;
|
|
|
+
|
|
|
+ aer_severity = cper_severity_to_aer(cper_severity);
|
|
|
+ if (aer_severity == AER_CORRECTABLE) {
|
|
|
+ status = aer->cor_status;
|
|
|
+ mask = aer->cor_mask;
|
|
|
+ status_strs = aer_correctable_error_string;
|
|
|
+ status_strs_size = ARRAY_SIZE(aer_correctable_error_string);
|
|
|
+ } else {
|
|
|
+ status = aer->uncor_status;
|
|
|
+ mask = aer->uncor_mask;
|
|
|
+ status_strs = aer_uncorrectable_error_string;
|
|
|
+ status_strs_size = ARRAY_SIZE(aer_uncorrectable_error_string);
|
|
|
+ tlp_header_valid = status & AER_LOG_TLP_MASKS;
|
|
|
+ }
|
|
|
+ layer = AER_GET_LAYER_ERROR(aer_severity, status);
|
|
|
+ agent = AER_GET_AGENT(aer_severity, status);
|
|
|
+ printk("%s""aer_status: 0x%08x, aer_mask: 0x%08x\n",
|
|
|
+ prefix, status, mask);
|
|
|
+ cper_print_bits(prefix, status, status_strs, status_strs_size);
|
|
|
+ printk("%s""aer_layer=%s, aer_agent=%s\n", prefix,
|
|
|
+ aer_error_layer[layer], aer_agent_string[agent]);
|
|
|
+ if (aer_severity != AER_CORRECTABLE)
|
|
|
+ printk("%s""aer_uncor_severity: 0x%08x\n",
|
|
|
+ prefix, aer->uncor_severity);
|
|
|
+ if (tlp_header_valid) {
|
|
|
+ const unsigned char *tlp;
|
|
|
+ tlp = (const unsigned char *)&aer->header_log;
|
|
|
+ printk("%s""aer_tlp_header:"
|
|
|
+ " %02x%02x%02x%02x %02x%02x%02x%02x"
|
|
|
+ " %02x%02x%02x%02x %02x%02x%02x%02x\n",
|
|
|
+ prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
|
|
|
+ *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
|
|
|
+ *(tlp + 11), *(tlp + 10), *(tlp + 9),
|
|
|
+ *(tlp + 8), *(tlp + 15), *(tlp + 14),
|
|
|
+ *(tlp + 13), *(tlp + 12));
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif
|