Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25076246 authored by Len Brown's avatar Len Brown
Browse files

Merge branch 'apei-release' into release

parents 05534c9f c413d768
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -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 | \
@@ -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:
+26 −16
Original line number Diff line number Diff line
@@ -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 */
+7 −0
Original line number Diff line number Diff line
@@ -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
+14 −4
Original line number Diff line number Diff line
@@ -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
@@ -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;
@@ -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;
@@ -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,
@@ -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[] = {
@@ -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
+21 −3
Original line number Diff line number Diff line
@@ -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;
@@ -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 */
@@ -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