|
@@ -29,6 +29,7 @@
|
|
#include <linux/time.h>
|
|
#include <linux/time.h>
|
|
#include <linux/cper.h>
|
|
#include <linux/cper.h>
|
|
#include <linux/acpi.h>
|
|
#include <linux/acpi.h>
|
|
|
|
+#include <linux/aer.h>
|
|
|
|
|
|
/*
|
|
/*
|
|
* CPER record ID need to be unique even after reboot, because record
|
|
* CPER record ID need to be unique even after reboot, because record
|
|
@@ -70,8 +71,8 @@ static const char *cper_severity_str(unsigned int severity)
|
|
* If the output length is longer than 80, multiple line will be
|
|
* If the output length is longer than 80, multiple line will be
|
|
* printed, with @pfx is printed at the beginning of each line.
|
|
* printed, with @pfx is printed at the beginning of each line.
|
|
*/
|
|
*/
|
|
-static void cper_print_bits(const char *pfx, unsigned int bits,
|
|
|
|
- const char *strs[], unsigned int strs_size)
|
|
|
|
|
|
+void cper_print_bits(const char *pfx, unsigned int bits,
|
|
|
|
+ const char *strs[], unsigned int strs_size)
|
|
{
|
|
{
|
|
int i, len = 0;
|
|
int i, len = 0;
|
|
const char *str;
|
|
const char *str;
|
|
@@ -81,6 +82,8 @@ static void cper_print_bits(const char *pfx, unsigned int bits,
|
|
if (!(bits & (1U << i)))
|
|
if (!(bits & (1U << i)))
|
|
continue;
|
|
continue;
|
|
str = strs[i];
|
|
str = strs[i];
|
|
|
|
+ if (!str)
|
|
|
|
+ continue;
|
|
if (len && len + strlen(str) + 2 > 80) {
|
|
if (len && len + strlen(str) + 2 > 80) {
|
|
printk("%s\n", buf);
|
|
printk("%s\n", buf);
|
|
len = 0;
|
|
len = 0;
|
|
@@ -243,7 +246,8 @@ static const char *cper_pcie_port_type_strs[] = {
|
|
"root complex event collector",
|
|
"root complex event collector",
|
|
};
|
|
};
|
|
|
|
|
|
-static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie)
|
|
|
|
|
|
+static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
|
|
|
|
+ const struct acpi_hest_generic_data *gdata)
|
|
{
|
|
{
|
|
if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
|
|
if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
|
|
printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
|
|
printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
|
|
@@ -276,6 +280,12 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie)
|
|
printk(
|
|
printk(
|
|
"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
|
|
"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
|
|
pfx, pcie->bridge.secondary_status, pcie->bridge.control);
|
|
pfx, pcie->bridge.secondary_status, pcie->bridge.control);
|
|
|
|
+#ifdef CONFIG_ACPI_APEI_PCIEAER
|
|
|
|
+ if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) {
|
|
|
|
+ struct aer_capability_regs *aer_regs = (void *)pcie->aer_info;
|
|
|
|
+ cper_print_aer(pfx, gdata->error_severity, aer_regs);
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
}
|
|
}
|
|
|
|
|
|
static const char *apei_estatus_section_flag_strs[] = {
|
|
static const char *apei_estatus_section_flag_strs[] = {
|
|
@@ -322,7 +332,7 @@ static void apei_estatus_print_section(
|
|
struct cper_sec_pcie *pcie = (void *)(gdata + 1);
|
|
struct cper_sec_pcie *pcie = (void *)(gdata + 1);
|
|
printk("%s""section_type: PCIe error\n", pfx);
|
|
printk("%s""section_type: PCIe error\n", pfx);
|
|
if (gdata->error_data_length >= sizeof(*pcie))
|
|
if (gdata->error_data_length >= sizeof(*pcie))
|
|
- cper_print_pcie(pfx, pcie);
|
|
|
|
|
|
+ cper_print_pcie(pfx, pcie, gdata);
|
|
else
|
|
else
|
|
goto err_section_too_small;
|
|
goto err_section_too_small;
|
|
} else
|
|
} else
|