Skip to content

Commit

Permalink
Merge branch 'apei-release' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
Len Brown committed Mar 22, 2011
2 parents 05534c9 + c413d76 commit 2507624
Show file tree
Hide file tree
Showing 11 changed files with 421 additions and 152 deletions.
25 changes: 25 additions & 0 deletions Documentation/acpi/apei/output_format.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,38 @@ 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 | \
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:
Expand Down
42 changes: 26 additions & 16 deletions arch/x86/kernel/cpu/mcheck/mce-apei.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
7 changes: 7 additions & 0 deletions drivers/acpi/apei/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 14 additions & 4 deletions drivers/acpi/apei/cper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
* 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;
const char *str;
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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
Expand Down
24 changes: 21 additions & 3 deletions drivers/acpi/apei/erst-dbg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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,
Expand Down
Loading

0 comments on commit 2507624

Please sign in to comment.