Loading Documentation/acpi/apei/output_format.txt +25 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,11 @@ vendor_id: <integer>, device_id: <integer> class_code: <integer>] [serial number: <integer>, <integer>] [bridge: secondary_status: <integer>, control: <integer>] [aer_status: <integer>, aer_mask: <integer> <aer status string> [aer_uncor_severity: <integer>] aer_layer=<aer layer string>, aer_agent=<aer agent string> aer_tlp_header: <integer> <integer> <integer> <integer>] <pcie port type string>* := PCIe end point | legacy PCI end point | \ unknown | unknown | root port | upstream switch port | \ Loading @@ -99,6 +104,26 @@ downstream switch port | PCIe to PCI/PCI-X bridge | \ PCI/PCI-X to PCIe bridge | root complex integrated endpoint device | \ root complex event collector if section severity is fatal or recoverable <aer status string># := unknown | unknown | unknown | unknown | Data Link Protocol | \ unknown | unknown | unknown | unknown | unknown | unknown | unknown | \ Poisoned TLP | Flow Control Protocol | Completion Timeout | \ Completer Abort | Unexpected Completion | Receiver Overflow | \ Malformed TLP | ECRC | Unsupported Request else <aer status string># := Receiver Error | unknown | unknown | unknown | unknown | unknown | \ Bad TLP | Bad DLLP | RELAY_NUM Rollover | unknown | unknown | unknown | \ Replay Timer Timeout | Advisory Non-Fatal fi <aer layer string> := Physical Layer | Data Link Layer | Transaction Layer <aer agent string> := Receiver ID | Requester ID | Completer ID | Transmitter ID Where, [] designate corresponding content is optional All <field string> description with * has the following format: Loading arch/x86/kernel/cpu/mcheck/mce-apei.c +26 −16 Original line number Diff line number Diff line Loading @@ -106,24 +106,34 @@ int apei_write_mce(struct mce *m) ssize_t apei_read_mce(struct mce *m, u64 *record_id) { struct cper_mce_record rcd; ssize_t len; len = erst_read_next(&rcd.hdr, sizeof(rcd)); if (len <= 0) return len; /* Can not skip other records in storage via ERST unless clear them */ else if (len != sizeof(rcd) || uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE)) { if (printk_ratelimit()) pr_warning( "MCE-APEI: Can not skip the unknown record in ERST"); return -EIO; } int rc, pos; rc = erst_get_record_id_begin(&pos); if (rc) return rc; retry: rc = erst_get_record_id_next(&pos, record_id); if (rc) goto out; /* no more record */ if (*record_id == APEI_ERST_INVALID_RECORD_ID) goto out; rc = erst_read(*record_id, &rcd.hdr, sizeof(rcd)); /* someone else has cleared the record, try next one */ if (rc == -ENOENT) goto retry; else if (rc < 0) goto out; /* try to skip other type records in storage */ else if (rc != sizeof(rcd) || uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE)) goto retry; memcpy(m, &rcd.mce, sizeof(*m)); *record_id = rcd.hdr.record_id; rc = sizeof(*m); out: erst_get_record_id_end(); return sizeof(*m); return rc; } /* Check whether there is record in ERST */ Loading drivers/acpi/apei/Kconfig +7 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,13 @@ config ACPI_APEI_GHES by firmware to produce more valuable hardware error information for Linux. config ACPI_APEI_PCIEAER bool "APEI PCIe AER logging/recovering support" depends on ACPI_APEI && PCIEAER help PCIe AER errors may be reported via APEI firmware first mode. Turn on this option to enable the corresponding support. config ACPI_APEI_EINJ tristate "APEI Error INJection (EINJ)" depends on ACPI_APEI && DEBUG_FS Loading drivers/acpi/apei/cper.c +14 −4 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <linux/time.h> #include <linux/cper.h> #include <linux/acpi.h> #include <linux/aer.h> /* * CPER record ID need to be unique even after reboot, because record Loading Loading @@ -70,7 +71,7 @@ static const char *cper_severity_str(unsigned int severity) * If the output length is longer than 80, multiple line will be * printed, with @pfx is printed at the beginning of each line. */ static void cper_print_bits(const char *pfx, unsigned int bits, void cper_print_bits(const char *pfx, unsigned int bits, const char *strs[], unsigned int strs_size) { int i, len = 0; Loading @@ -81,6 +82,8 @@ static void cper_print_bits(const char *pfx, unsigned int bits, if (!(bits & (1U << i))) continue; str = strs[i]; if (!str) continue; if (len && len + strlen(str) + 2 > 80) { printk("%s\n", buf); len = 0; Loading Loading @@ -243,7 +246,8 @@ static const char *cper_pcie_port_type_strs[] = { "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) printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, Loading Loading @@ -276,6 +280,12 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie) printk( "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", 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[] = { Loading Loading @@ -322,7 +332,7 @@ static void apei_estatus_print_section( struct cper_sec_pcie *pcie = (void *)(gdata + 1); printk("%s""section_type: PCIe error\n", pfx); if (gdata->error_data_length >= sizeof(*pcie)) cper_print_pcie(pfx, pcie); cper_print_pcie(pfx, pcie, gdata); else goto err_section_too_small; } else Loading drivers/acpi/apei/erst-dbg.c +21 −3 Original line number Diff line number Diff line Loading @@ -43,12 +43,27 @@ static DEFINE_MUTEX(erst_dbg_mutex); static int erst_dbg_open(struct inode *inode, struct file *file) { int rc, *pos; if (erst_disable) return -ENODEV; pos = (int *)&file->private_data; rc = erst_get_record_id_begin(pos); if (rc) return rc; return nonseekable_open(inode, file); } static int erst_dbg_release(struct inode *inode, struct file *file) { erst_get_record_id_end(); return 0; } static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { int rc; Loading Loading @@ -79,18 +94,20 @@ static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg) static ssize_t erst_dbg_read(struct file *filp, char __user *ubuf, size_t usize, loff_t *off) { int rc; int rc, *pos; ssize_t len = 0; u64 id; if (*off != 0) if (*off) return -EINVAL; if (mutex_lock_interruptible(&erst_dbg_mutex) != 0) return -EINTR; pos = (int *)&filp->private_data; retry_next: rc = erst_get_next_record_id(&id); rc = erst_get_record_id_next(pos, &id); if (rc) goto out; /* no more record */ Loading Loading @@ -181,6 +198,7 @@ static ssize_t erst_dbg_write(struct file *filp, const char __user *ubuf, static const struct file_operations erst_dbg_ops = { .owner = THIS_MODULE, .open = erst_dbg_open, .release = erst_dbg_release, .read = erst_dbg_read, .write = erst_dbg_write, .unlocked_ioctl = erst_dbg_ioctl, Loading Loading
Documentation/acpi/apei/output_format.txt +25 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,11 @@ vendor_id: <integer>, device_id: <integer> class_code: <integer>] [serial number: <integer>, <integer>] [bridge: secondary_status: <integer>, control: <integer>] [aer_status: <integer>, aer_mask: <integer> <aer status string> [aer_uncor_severity: <integer>] aer_layer=<aer layer string>, aer_agent=<aer agent string> aer_tlp_header: <integer> <integer> <integer> <integer>] <pcie port type string>* := PCIe end point | legacy PCI end point | \ unknown | unknown | root port | upstream switch port | \ Loading @@ -99,6 +104,26 @@ downstream switch port | PCIe to PCI/PCI-X bridge | \ PCI/PCI-X to PCIe bridge | root complex integrated endpoint device | \ root complex event collector if section severity is fatal or recoverable <aer status string># := unknown | unknown | unknown | unknown | Data Link Protocol | \ unknown | unknown | unknown | unknown | unknown | unknown | unknown | \ Poisoned TLP | Flow Control Protocol | Completion Timeout | \ Completer Abort | Unexpected Completion | Receiver Overflow | \ Malformed TLP | ECRC | Unsupported Request else <aer status string># := Receiver Error | unknown | unknown | unknown | unknown | unknown | \ Bad TLP | Bad DLLP | RELAY_NUM Rollover | unknown | unknown | unknown | \ Replay Timer Timeout | Advisory Non-Fatal fi <aer layer string> := Physical Layer | Data Link Layer | Transaction Layer <aer agent string> := Receiver ID | Requester ID | Completer ID | Transmitter ID Where, [] designate corresponding content is optional All <field string> description with * has the following format: Loading
arch/x86/kernel/cpu/mcheck/mce-apei.c +26 −16 Original line number Diff line number Diff line Loading @@ -106,24 +106,34 @@ int apei_write_mce(struct mce *m) ssize_t apei_read_mce(struct mce *m, u64 *record_id) { struct cper_mce_record rcd; ssize_t len; len = erst_read_next(&rcd.hdr, sizeof(rcd)); if (len <= 0) return len; /* Can not skip other records in storage via ERST unless clear them */ else if (len != sizeof(rcd) || uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE)) { if (printk_ratelimit()) pr_warning( "MCE-APEI: Can not skip the unknown record in ERST"); return -EIO; } int rc, pos; rc = erst_get_record_id_begin(&pos); if (rc) return rc; retry: rc = erst_get_record_id_next(&pos, record_id); if (rc) goto out; /* no more record */ if (*record_id == APEI_ERST_INVALID_RECORD_ID) goto out; rc = erst_read(*record_id, &rcd.hdr, sizeof(rcd)); /* someone else has cleared the record, try next one */ if (rc == -ENOENT) goto retry; else if (rc < 0) goto out; /* try to skip other type records in storage */ else if (rc != sizeof(rcd) || uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE)) goto retry; memcpy(m, &rcd.mce, sizeof(*m)); *record_id = rcd.hdr.record_id; rc = sizeof(*m); out: erst_get_record_id_end(); return sizeof(*m); return rc; } /* Check whether there is record in ERST */ Loading
drivers/acpi/apei/Kconfig +7 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,13 @@ config ACPI_APEI_GHES by firmware to produce more valuable hardware error information for Linux. config ACPI_APEI_PCIEAER bool "APEI PCIe AER logging/recovering support" depends on ACPI_APEI && PCIEAER help PCIe AER errors may be reported via APEI firmware first mode. Turn on this option to enable the corresponding support. config ACPI_APEI_EINJ tristate "APEI Error INJection (EINJ)" depends on ACPI_APEI && DEBUG_FS Loading
drivers/acpi/apei/cper.c +14 −4 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <linux/time.h> #include <linux/cper.h> #include <linux/acpi.h> #include <linux/aer.h> /* * CPER record ID need to be unique even after reboot, because record Loading Loading @@ -70,7 +71,7 @@ static const char *cper_severity_str(unsigned int severity) * If the output length is longer than 80, multiple line will be * printed, with @pfx is printed at the beginning of each line. */ static void cper_print_bits(const char *pfx, unsigned int bits, void cper_print_bits(const char *pfx, unsigned int bits, const char *strs[], unsigned int strs_size) { int i, len = 0; Loading @@ -81,6 +82,8 @@ static void cper_print_bits(const char *pfx, unsigned int bits, if (!(bits & (1U << i))) continue; str = strs[i]; if (!str) continue; if (len && len + strlen(str) + 2 > 80) { printk("%s\n", buf); len = 0; Loading Loading @@ -243,7 +246,8 @@ static const char *cper_pcie_port_type_strs[] = { "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) printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, Loading Loading @@ -276,6 +280,12 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie) printk( "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", 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[] = { Loading Loading @@ -322,7 +332,7 @@ static void apei_estatus_print_section( struct cper_sec_pcie *pcie = (void *)(gdata + 1); printk("%s""section_type: PCIe error\n", pfx); if (gdata->error_data_length >= sizeof(*pcie)) cper_print_pcie(pfx, pcie); cper_print_pcie(pfx, pcie, gdata); else goto err_section_too_small; } else Loading
drivers/acpi/apei/erst-dbg.c +21 −3 Original line number Diff line number Diff line Loading @@ -43,12 +43,27 @@ static DEFINE_MUTEX(erst_dbg_mutex); static int erst_dbg_open(struct inode *inode, struct file *file) { int rc, *pos; if (erst_disable) return -ENODEV; pos = (int *)&file->private_data; rc = erst_get_record_id_begin(pos); if (rc) return rc; return nonseekable_open(inode, file); } static int erst_dbg_release(struct inode *inode, struct file *file) { erst_get_record_id_end(); return 0; } static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { int rc; Loading Loading @@ -79,18 +94,20 @@ static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg) static ssize_t erst_dbg_read(struct file *filp, char __user *ubuf, size_t usize, loff_t *off) { int rc; int rc, *pos; ssize_t len = 0; u64 id; if (*off != 0) if (*off) return -EINVAL; if (mutex_lock_interruptible(&erst_dbg_mutex) != 0) return -EINTR; pos = (int *)&filp->private_data; retry_next: rc = erst_get_next_record_id(&id); rc = erst_get_record_id_next(pos, &id); if (rc) goto out; /* no more record */ Loading Loading @@ -181,6 +198,7 @@ static ssize_t erst_dbg_write(struct file *filp, const char __user *ubuf, static const struct file_operations erst_dbg_ops = { .owner = THIS_MODULE, .open = erst_dbg_open, .release = erst_dbg_release, .read = erst_dbg_read, .write = erst_dbg_write, .unlocked_ioctl = erst_dbg_ioctl, Loading