mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-15 03:41:32 -04:00
Merge branch 'pci/aer'
- Initialize struct aer_err_info before using it to avoid depending on stack garbage (Bjorn Helgaas) - Log the DPC Error Source ID only when it's actually valid (when ERR_FATAL or ERR_NONFATAL was received from a downstream device) and decode into bus/device/function (Bjorn Helgaas) - Consolidate AER Error Source ID in one place for message consistency (Bjorn Helgaas) - Update statistics and emit trace events early in AER logging paths, before any potential ratelimiting (Bjorn Helgaas) - Determine AER log level once and save it so all related messages use the same level (Karolina Stolarek) - Use KERN_WARNING, not KERN_ERR, when logging PCIe Correctable Errors. - Ratelimit PCIe Correctable and Non-Fatal error logging, with sysfs controls on interval and burst count, to avoid flooding logs and RCU stall warnings (Jon Pan-Doh) * pci/aer: PCI/ERR: Remove misleading TODO regarding kernel panic PCI/AER: Add sysfs attributes for log ratelimits PCI/AER: Add ratelimits to PCI AER Documentation PCI/AER: Ratelimit correctable and non-fatal error logging PCI/AER: Simplify add_error_device() PCI/AER: Convert aer_get_device_error_info(), aer_print_error() to index PCI/AER: Rename struct aer_stats to aer_info PCI/AER: Reduce pci_print_aer() correctable error level to KERN_WARNING PCI/ERR: Add printk level to pcie_print_tlp_log() PCI/AER: Check log level once and remember it PCI/AER: Trace error event before ratelimiting PCI/AER: Update statistics before ratelimiting PCI/AER: Simplify pci_print_aer() PCI/AER: Initialize aer_err_info before using it PCI/AER: Move aer_print_source() earlier in file PCI/AER: Rename aer_print_port_info() to aer_print_source() PCI/AER: Extract bus/dev/fn in aer_print_port_info() with PCI_BUS_NUM(), etc PCI/AER: Consolidate Error Source ID logging in aer_isr_one_error_type() PCI/AER: Factor COR/UNCOR error handling out from aer_isr_one_error() PCI/DPC: Log Error Source ID only when valid PCI/DPC: Initialize aer_err_info before using it
This commit is contained in:
@@ -117,3 +117,47 @@ Date: July 2018
|
||||
KernelVersion: 4.19.0
|
||||
Contact: linux-pci@vger.kernel.org, rajatja@google.com
|
||||
Description: Total number of ERR_NONFATAL messages reported to rootport.
|
||||
|
||||
PCIe AER ratelimits
|
||||
-------------------
|
||||
|
||||
These attributes show up under all the devices that are AER capable.
|
||||
They represent configurable ratelimits of logs per error type.
|
||||
|
||||
See Documentation/PCI/pcieaer-howto.rst for more info on ratelimits.
|
||||
|
||||
What: /sys/bus/pci/devices/<dev>/aer/correctable_ratelimit_interval_ms
|
||||
Date: May 2025
|
||||
KernelVersion: 6.16.0
|
||||
Contact: linux-pci@vger.kernel.org
|
||||
Description: Writing 0 disables AER correctable error log ratelimiting.
|
||||
Writing a positive value sets the ratelimit interval in ms.
|
||||
Default is DEFAULT_RATELIMIT_INTERVAL (5000 ms).
|
||||
|
||||
What: /sys/bus/pci/devices/<dev>/aer/correctable_ratelimit_burst
|
||||
Date: May 2025
|
||||
KernelVersion: 6.16.0
|
||||
Contact: linux-pci@vger.kernel.org
|
||||
Description: Ratelimit burst for correctable error logs. Writing a value
|
||||
changes the number of errors (burst) allowed per interval
|
||||
before ratelimiting. Reading gets the current ratelimit
|
||||
burst. Default is DEFAULT_RATELIMIT_BURST (10).
|
||||
|
||||
What: /sys/bus/pci/devices/<dev>/aer/nonfatal_ratelimit_interval_ms
|
||||
Date: May 2025
|
||||
KernelVersion: 6.16.0
|
||||
Contact: linux-pci@vger.kernel.org
|
||||
Description: Writing 0 disables AER non-fatal uncorrectable error log
|
||||
ratelimiting. Writing a positive value sets the ratelimit
|
||||
interval in ms. Default is DEFAULT_RATELIMIT_INTERVAL
|
||||
(5000 ms).
|
||||
|
||||
What: /sys/bus/pci/devices/<dev>/aer/nonfatal_ratelimit_burst
|
||||
Date: May 2025
|
||||
KernelVersion: 6.16.0
|
||||
Contact: linux-pci@vger.kernel.org
|
||||
Description: Ratelimit burst for non-fatal uncorrectable error logs.
|
||||
Writing a value changes the number of errors (burst)
|
||||
allowed per interval before ratelimiting. Reading gets the
|
||||
current ratelimit burst. Default is DEFAULT_RATELIMIT_BURST
|
||||
(10).
|
||||
@@ -85,12 +85,27 @@ In the example, 'Requester ID' means the ID of the device that sent
|
||||
the error message to the Root Port. Please refer to PCIe specs for other
|
||||
fields.
|
||||
|
||||
AER Ratelimits
|
||||
--------------
|
||||
|
||||
Since error messages can be generated for each transaction, we may see
|
||||
large volumes of errors reported. To prevent spammy devices from flooding
|
||||
the console/stalling execution, messages are throttled by device and error
|
||||
type (correctable vs. non-fatal uncorrectable). Fatal errors, including
|
||||
DPC errors, are not ratelimited.
|
||||
|
||||
AER uses the default ratelimit of DEFAULT_RATELIMIT_BURST (10 events) over
|
||||
DEFAULT_RATELIMIT_INTERVAL (5 seconds).
|
||||
|
||||
Ratelimits are exposed in the form of sysfs attributes and configurable.
|
||||
See Documentation/ABI/testing/sysfs-bus-pci-devices-aer.
|
||||
|
||||
AER Statistics / Counters
|
||||
-------------------------
|
||||
|
||||
When PCIe AER errors are captured, the counters / statistics are also exposed
|
||||
in the form of sysfs attributes which are documented at
|
||||
Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats
|
||||
Documentation/ABI/testing/sysfs-bus-pci-devices-aer.
|
||||
|
||||
Developer Guide
|
||||
===============
|
||||
|
||||
@@ -1805,6 +1805,7 @@ const struct attribute_group *pci_dev_attr_groups[] = {
|
||||
&pcie_dev_attr_group,
|
||||
#ifdef CONFIG_PCIEAER
|
||||
&aer_stats_attr_group,
|
||||
&aer_attr_group,
|
||||
#endif
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
&aspm_ctrl_attr_group,
|
||||
|
||||
@@ -587,12 +587,15 @@ static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev)
|
||||
|
||||
struct aer_err_info {
|
||||
struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
|
||||
int ratelimit_print[AER_MAX_MULTI_ERR_DEVICES];
|
||||
int error_dev_num;
|
||||
const char *level; /* printk level */
|
||||
|
||||
unsigned int id:16;
|
||||
|
||||
unsigned int severity:2; /* 0:NONFATAL | 1:FATAL | 2:COR */
|
||||
unsigned int __pad1:5;
|
||||
unsigned int root_ratelimit_print:1; /* 0=skip, 1=print */
|
||||
unsigned int __pad1:4;
|
||||
unsigned int multi_error_valid:1;
|
||||
|
||||
unsigned int first_error:5;
|
||||
@@ -604,15 +607,16 @@ struct aer_err_info {
|
||||
struct pcie_tlp_log tlp; /* TLP Header */
|
||||
};
|
||||
|
||||
int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
|
||||
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
|
||||
int aer_get_device_error_info(struct aer_err_info *info, int i);
|
||||
void aer_print_error(struct aer_err_info *info, int i);
|
||||
|
||||
int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2,
|
||||
unsigned int tlp_len, bool flit,
|
||||
struct pcie_tlp_log *log);
|
||||
unsigned int aer_tlp_log_len(struct pci_dev *dev, u32 aercc);
|
||||
void pcie_print_tlp_log(const struct pci_dev *dev,
|
||||
const struct pcie_tlp_log *log, const char *pfx);
|
||||
const struct pcie_tlp_log *log, const char *level,
|
||||
const char *pfx);
|
||||
#endif /* CONFIG_PCIEAER */
|
||||
|
||||
#ifdef CONFIG_PCIEPORTBUS
|
||||
@@ -961,6 +965,7 @@ void pci_no_aer(void);
|
||||
void pci_aer_init(struct pci_dev *dev);
|
||||
void pci_aer_exit(struct pci_dev *dev);
|
||||
extern const struct attribute_group aer_stats_attr_group;
|
||||
extern const struct attribute_group aer_attr_group;
|
||||
void pci_aer_clear_fatal_status(struct pci_dev *dev);
|
||||
int pci_aer_clear_status(struct pci_dev *dev);
|
||||
int pci_aer_raw_clear_status(struct pci_dev *dev);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/slab.h>
|
||||
#include <acpi/apei.h>
|
||||
#include <acpi/ghes.h>
|
||||
@@ -54,8 +55,8 @@ struct aer_rpc {
|
||||
DECLARE_KFIFO(aer_fifo, struct aer_err_source, AER_ERROR_SOURCES_MAX);
|
||||
};
|
||||
|
||||
/* AER stats for the device */
|
||||
struct aer_stats {
|
||||
/* AER info for the device */
|
||||
struct aer_info {
|
||||
|
||||
/*
|
||||
* Fields for all AER capable devices. They indicate the errors
|
||||
@@ -88,6 +89,10 @@ struct aer_stats {
|
||||
u64 rootport_total_cor_errs;
|
||||
u64 rootport_total_fatal_errs;
|
||||
u64 rootport_total_nonfatal_errs;
|
||||
|
||||
/* Ratelimits for errors */
|
||||
struct ratelimit_state correctable_ratelimit;
|
||||
struct ratelimit_state nonfatal_ratelimit;
|
||||
};
|
||||
|
||||
#define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \
|
||||
@@ -377,7 +382,12 @@ void pci_aer_init(struct pci_dev *dev)
|
||||
if (!dev->aer_cap)
|
||||
return;
|
||||
|
||||
dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL);
|
||||
dev->aer_info = kzalloc(sizeof(*dev->aer_info), GFP_KERNEL);
|
||||
|
||||
ratelimit_state_init(&dev->aer_info->correctable_ratelimit,
|
||||
DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
|
||||
ratelimit_state_init(&dev->aer_info->nonfatal_ratelimit,
|
||||
DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
|
||||
|
||||
/*
|
||||
* We save/restore PCI_ERR_UNCOR_MASK, PCI_ERR_UNCOR_SEVER,
|
||||
@@ -398,8 +408,8 @@ void pci_aer_init(struct pci_dev *dev)
|
||||
|
||||
void pci_aer_exit(struct pci_dev *dev)
|
||||
{
|
||||
kfree(dev->aer_stats);
|
||||
dev->aer_stats = NULL;
|
||||
kfree(dev->aer_info);
|
||||
dev->aer_info = NULL;
|
||||
}
|
||||
|
||||
#define AER_AGENT_RECEIVER 0
|
||||
@@ -537,10 +547,10 @@ static const char *aer_agent_string[] = {
|
||||
{ \
|
||||
unsigned int i; \
|
||||
struct pci_dev *pdev = to_pci_dev(dev); \
|
||||
u64 *stats = pdev->aer_stats->stats_array; \
|
||||
u64 *stats = pdev->aer_info->stats_array; \
|
||||
size_t len = 0; \
|
||||
\
|
||||
for (i = 0; i < ARRAY_SIZE(pdev->aer_stats->stats_array); i++) {\
|
||||
for (i = 0; i < ARRAY_SIZE(pdev->aer_info->stats_array); i++) { \
|
||||
if (strings_array[i]) \
|
||||
len += sysfs_emit_at(buf, len, "%s %llu\n", \
|
||||
strings_array[i], \
|
||||
@@ -551,7 +561,7 @@ static const char *aer_agent_string[] = {
|
||||
i, stats[i]); \
|
||||
} \
|
||||
len += sysfs_emit_at(buf, len, "TOTAL_%s %llu\n", total_string, \
|
||||
pdev->aer_stats->total_field); \
|
||||
pdev->aer_info->total_field); \
|
||||
return len; \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(name)
|
||||
@@ -572,7 +582,7 @@ aer_stats_dev_attr(aer_dev_nonfatal, dev_nonfatal_errs,
|
||||
char *buf) \
|
||||
{ \
|
||||
struct pci_dev *pdev = to_pci_dev(dev); \
|
||||
return sysfs_emit(buf, "%llu\n", pdev->aer_stats->field); \
|
||||
return sysfs_emit(buf, "%llu\n", pdev->aer_info->field); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(name)
|
||||
|
||||
@@ -599,7 +609,7 @@ static umode_t aer_stats_attrs_are_visible(struct kobject *kobj,
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
||||
if (!pdev->aer_stats)
|
||||
if (!pdev->aer_info)
|
||||
return 0;
|
||||
|
||||
if ((a == &dev_attr_aer_rootport_total_err_cor.attr ||
|
||||
@@ -617,31 +627,136 @@ const struct attribute_group aer_stats_attr_group = {
|
||||
.is_visible = aer_stats_attrs_are_visible,
|
||||
};
|
||||
|
||||
/*
|
||||
* Ratelimit interval
|
||||
* <=0: disabled with ratelimit.interval = 0
|
||||
* >0: enabled with ratelimit.interval in ms
|
||||
*/
|
||||
#define aer_ratelimit_interval_attr(name, ratelimit) \
|
||||
static ssize_t \
|
||||
name##_show(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct pci_dev *pdev = to_pci_dev(dev); \
|
||||
\
|
||||
return sysfs_emit(buf, "%d\n", \
|
||||
pdev->aer_info->ratelimit.interval); \
|
||||
} \
|
||||
\
|
||||
static ssize_t \
|
||||
name##_store(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct pci_dev *pdev = to_pci_dev(dev); \
|
||||
int interval; \
|
||||
\
|
||||
if (!capable(CAP_SYS_ADMIN)) \
|
||||
return -EPERM; \
|
||||
\
|
||||
if (kstrtoint(buf, 0, &interval) < 0) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
if (interval <= 0) \
|
||||
interval = 0; \
|
||||
else \
|
||||
interval = msecs_to_jiffies(interval); \
|
||||
\
|
||||
pdev->aer_info->ratelimit.interval = interval; \
|
||||
\
|
||||
return count; \
|
||||
} \
|
||||
static DEVICE_ATTR_RW(name);
|
||||
|
||||
#define aer_ratelimit_burst_attr(name, ratelimit) \
|
||||
static ssize_t \
|
||||
name##_show(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct pci_dev *pdev = to_pci_dev(dev); \
|
||||
\
|
||||
return sysfs_emit(buf, "%d\n", \
|
||||
pdev->aer_info->ratelimit.burst); \
|
||||
} \
|
||||
\
|
||||
static ssize_t \
|
||||
name##_store(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct pci_dev *pdev = to_pci_dev(dev); \
|
||||
int burst; \
|
||||
\
|
||||
if (!capable(CAP_SYS_ADMIN)) \
|
||||
return -EPERM; \
|
||||
\
|
||||
if (kstrtoint(buf, 0, &burst) < 0) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
pdev->aer_info->ratelimit.burst = burst; \
|
||||
\
|
||||
return count; \
|
||||
} \
|
||||
static DEVICE_ATTR_RW(name);
|
||||
|
||||
#define aer_ratelimit_attrs(name) \
|
||||
aer_ratelimit_interval_attr(name##_ratelimit_interval_ms, \
|
||||
name##_ratelimit) \
|
||||
aer_ratelimit_burst_attr(name##_ratelimit_burst, \
|
||||
name##_ratelimit)
|
||||
|
||||
aer_ratelimit_attrs(correctable)
|
||||
aer_ratelimit_attrs(nonfatal)
|
||||
|
||||
static struct attribute *aer_attrs[] = {
|
||||
&dev_attr_correctable_ratelimit_interval_ms.attr,
|
||||
&dev_attr_correctable_ratelimit_burst.attr,
|
||||
&dev_attr_nonfatal_ratelimit_interval_ms.attr,
|
||||
&dev_attr_nonfatal_ratelimit_burst.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static umode_t aer_attrs_are_visible(struct kobject *kobj,
|
||||
struct attribute *a, int n)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
||||
if (!pdev->aer_info)
|
||||
return 0;
|
||||
|
||||
return a->mode;
|
||||
}
|
||||
|
||||
const struct attribute_group aer_attr_group = {
|
||||
.name = "aer",
|
||||
.attrs = aer_attrs,
|
||||
.is_visible = aer_attrs_are_visible,
|
||||
};
|
||||
|
||||
static void pci_dev_aer_stats_incr(struct pci_dev *pdev,
|
||||
struct aer_err_info *info)
|
||||
{
|
||||
unsigned long status = info->status & ~info->mask;
|
||||
int i, max = -1;
|
||||
u64 *counter = NULL;
|
||||
struct aer_stats *aer_stats = pdev->aer_stats;
|
||||
struct aer_info *aer_info = pdev->aer_info;
|
||||
|
||||
if (!aer_stats)
|
||||
if (!aer_info)
|
||||
return;
|
||||
|
||||
switch (info->severity) {
|
||||
case AER_CORRECTABLE:
|
||||
aer_stats->dev_total_cor_errs++;
|
||||
counter = &aer_stats->dev_cor_errs[0];
|
||||
aer_info->dev_total_cor_errs++;
|
||||
counter = &aer_info->dev_cor_errs[0];
|
||||
max = AER_MAX_TYPEOF_COR_ERRS;
|
||||
break;
|
||||
case AER_NONFATAL:
|
||||
aer_stats->dev_total_nonfatal_errs++;
|
||||
counter = &aer_stats->dev_nonfatal_errs[0];
|
||||
aer_info->dev_total_nonfatal_errs++;
|
||||
counter = &aer_info->dev_nonfatal_errs[0];
|
||||
max = AER_MAX_TYPEOF_UNCOR_ERRS;
|
||||
break;
|
||||
case AER_FATAL:
|
||||
aer_stats->dev_total_fatal_errs++;
|
||||
counter = &aer_stats->dev_fatal_errs[0];
|
||||
aer_info->dev_total_fatal_errs++;
|
||||
counter = &aer_info->dev_fatal_errs[0];
|
||||
max = AER_MAX_TYPEOF_UNCOR_ERRS;
|
||||
break;
|
||||
}
|
||||
@@ -653,37 +768,46 @@ static void pci_dev_aer_stats_incr(struct pci_dev *pdev,
|
||||
static void pci_rootport_aer_stats_incr(struct pci_dev *pdev,
|
||||
struct aer_err_source *e_src)
|
||||
{
|
||||
struct aer_stats *aer_stats = pdev->aer_stats;
|
||||
struct aer_info *aer_info = pdev->aer_info;
|
||||
|
||||
if (!aer_stats)
|
||||
if (!aer_info)
|
||||
return;
|
||||
|
||||
if (e_src->status & PCI_ERR_ROOT_COR_RCV)
|
||||
aer_stats->rootport_total_cor_errs++;
|
||||
aer_info->rootport_total_cor_errs++;
|
||||
|
||||
if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) {
|
||||
if (e_src->status & PCI_ERR_ROOT_FATAL_RCV)
|
||||
aer_stats->rootport_total_fatal_errs++;
|
||||
aer_info->rootport_total_fatal_errs++;
|
||||
else
|
||||
aer_stats->rootport_total_nonfatal_errs++;
|
||||
aer_info->rootport_total_nonfatal_errs++;
|
||||
}
|
||||
}
|
||||
|
||||
static void __aer_print_error(struct pci_dev *dev,
|
||||
struct aer_err_info *info)
|
||||
static int aer_ratelimit(struct pci_dev *dev, unsigned int severity)
|
||||
{
|
||||
switch (severity) {
|
||||
case AER_NONFATAL:
|
||||
return __ratelimit(&dev->aer_info->nonfatal_ratelimit);
|
||||
case AER_CORRECTABLE:
|
||||
return __ratelimit(&dev->aer_info->correctable_ratelimit);
|
||||
default:
|
||||
return 1; /* Don't ratelimit fatal errors */
|
||||
}
|
||||
}
|
||||
|
||||
static void __aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
|
||||
{
|
||||
const char **strings;
|
||||
unsigned long status = info->status & ~info->mask;
|
||||
const char *level, *errmsg;
|
||||
const char *level = info->level;
|
||||
const char *errmsg;
|
||||
int i;
|
||||
|
||||
if (info->severity == AER_CORRECTABLE) {
|
||||
if (info->severity == AER_CORRECTABLE)
|
||||
strings = aer_correctable_error_string;
|
||||
level = KERN_WARNING;
|
||||
} else {
|
||||
else
|
||||
strings = aer_uncorrectable_error_string;
|
||||
level = KERN_ERR;
|
||||
}
|
||||
|
||||
for_each_set_bit(i, &status, 32) {
|
||||
errmsg = strings[i];
|
||||
@@ -693,14 +817,39 @@ static void __aer_print_error(struct pci_dev *dev,
|
||||
aer_printk(level, dev, " [%2d] %-22s%s\n", i, errmsg,
|
||||
info->first_error == i ? " (First)" : "");
|
||||
}
|
||||
pci_dev_aer_stats_incr(dev, info);
|
||||
}
|
||||
|
||||
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
|
||||
static void aer_print_source(struct pci_dev *dev, struct aer_err_info *info,
|
||||
bool found)
|
||||
{
|
||||
int layer, agent;
|
||||
int id = pci_dev_id(dev);
|
||||
const char *level;
|
||||
u16 source = info->id;
|
||||
|
||||
pci_info(dev, "%s%s error message received from %04x:%02x:%02x.%d%s\n",
|
||||
info->multi_error_valid ? "Multiple " : "",
|
||||
aer_error_severity_string[info->severity],
|
||||
pci_domain_nr(dev->bus), PCI_BUS_NUM(source),
|
||||
PCI_SLOT(source), PCI_FUNC(source),
|
||||
found ? "" : " (no details found");
|
||||
}
|
||||
|
||||
void aer_print_error(struct aer_err_info *info, int i)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
int layer, agent, id;
|
||||
const char *level = info->level;
|
||||
|
||||
if (WARN_ON_ONCE(i >= AER_MAX_MULTI_ERR_DEVICES))
|
||||
return;
|
||||
|
||||
dev = info->dev[i];
|
||||
id = pci_dev_id(dev);
|
||||
|
||||
pci_dev_aer_stats_incr(dev, info);
|
||||
trace_aer_event(pci_name(dev), (info->status & ~info->mask),
|
||||
info->severity, info->tlp_header_valid, &info->tlp);
|
||||
|
||||
if (!info->ratelimit_print[i])
|
||||
return;
|
||||
|
||||
if (!info->status) {
|
||||
pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
|
||||
@@ -711,8 +860,6 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
|
||||
layer = AER_GET_LAYER_ERROR(info->severity, info->status);
|
||||
agent = AER_GET_AGENT(info->severity, info->status);
|
||||
|
||||
level = (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR;
|
||||
|
||||
aer_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
|
||||
aer_error_severity_string[info->severity],
|
||||
aer_error_layer[layer], aer_agent_string[agent]);
|
||||
@@ -723,26 +870,11 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
|
||||
__aer_print_error(dev, info);
|
||||
|
||||
if (info->tlp_header_valid)
|
||||
pcie_print_tlp_log(dev, &info->tlp, dev_fmt(" "));
|
||||
pcie_print_tlp_log(dev, &info->tlp, level, dev_fmt(" "));
|
||||
|
||||
out:
|
||||
if (info->id && info->error_dev_num > 1 && info->id == id)
|
||||
pci_err(dev, " Error of this Agent is reported first\n");
|
||||
|
||||
trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
|
||||
info->severity, info->tlp_header_valid, &info->tlp);
|
||||
}
|
||||
|
||||
static void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
|
||||
{
|
||||
u8 bus = info->id >> 8;
|
||||
u8 devfn = info->id & 0xff;
|
||||
|
||||
pci_info(dev, "%s%s error message received from %04x:%02x:%02x.%d\n",
|
||||
info->multi_error_valid ? "Multiple " : "",
|
||||
aer_error_severity_string[info->severity],
|
||||
pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn),
|
||||
PCI_FUNC(devfn));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI_APEI_PCIEAER
|
||||
@@ -765,40 +897,48 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
|
||||
{
|
||||
int layer, agent, tlp_header_valid = 0;
|
||||
u32 status, mask;
|
||||
struct aer_err_info info;
|
||||
struct aer_err_info info = {
|
||||
.severity = aer_severity,
|
||||
.first_error = PCI_ERR_CAP_FEP(aer->cap_control),
|
||||
};
|
||||
|
||||
if (aer_severity == AER_CORRECTABLE) {
|
||||
status = aer->cor_status;
|
||||
mask = aer->cor_mask;
|
||||
info.level = KERN_WARNING;
|
||||
} else {
|
||||
status = aer->uncor_status;
|
||||
mask = aer->uncor_mask;
|
||||
info.level = KERN_ERR;
|
||||
tlp_header_valid = status & AER_LOG_TLP_MASKS;
|
||||
}
|
||||
|
||||
info.status = status;
|
||||
info.mask = mask;
|
||||
|
||||
pci_dev_aer_stats_incr(dev, &info);
|
||||
trace_aer_event(pci_name(dev), (status & ~mask),
|
||||
aer_severity, tlp_header_valid, &aer->header_log);
|
||||
|
||||
if (!aer_ratelimit(dev, info.severity))
|
||||
return;
|
||||
|
||||
layer = AER_GET_LAYER_ERROR(aer_severity, status);
|
||||
agent = AER_GET_AGENT(aer_severity, status);
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.severity = aer_severity;
|
||||
info.status = status;
|
||||
info.mask = mask;
|
||||
info.first_error = PCI_ERR_CAP_FEP(aer->cap_control);
|
||||
|
||||
pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask);
|
||||
aer_printk(info.level, dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n",
|
||||
status, mask);
|
||||
__aer_print_error(dev, &info);
|
||||
pci_err(dev, "aer_layer=%s, aer_agent=%s\n",
|
||||
aer_error_layer[layer], aer_agent_string[agent]);
|
||||
aer_printk(info.level, dev, "aer_layer=%s, aer_agent=%s\n",
|
||||
aer_error_layer[layer], aer_agent_string[agent]);
|
||||
|
||||
if (aer_severity != AER_CORRECTABLE)
|
||||
pci_err(dev, "aer_uncor_severity: 0x%08x\n",
|
||||
aer->uncor_severity);
|
||||
aer_printk(info.level, dev, "aer_uncor_severity: 0x%08x\n",
|
||||
aer->uncor_severity);
|
||||
|
||||
if (tlp_header_valid)
|
||||
pcie_print_tlp_log(dev, &aer->header_log, dev_fmt(" "));
|
||||
|
||||
trace_aer_event(dev_name(&dev->dev), (status & ~mask),
|
||||
aer_severity, tlp_header_valid, &aer->header_log);
|
||||
pcie_print_tlp_log(dev, &aer->header_log, info.level,
|
||||
dev_fmt(" "));
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL");
|
||||
|
||||
@@ -809,12 +949,27 @@ EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL");
|
||||
*/
|
||||
static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev)
|
||||
{
|
||||
if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) {
|
||||
e_info->dev[e_info->error_dev_num] = pci_dev_get(dev);
|
||||
e_info->error_dev_num++;
|
||||
return 0;
|
||||
int i = e_info->error_dev_num;
|
||||
|
||||
if (i >= AER_MAX_MULTI_ERR_DEVICES)
|
||||
return -ENOSPC;
|
||||
|
||||
e_info->dev[i] = pci_dev_get(dev);
|
||||
e_info->error_dev_num++;
|
||||
|
||||
/*
|
||||
* Ratelimit AER log messages. "dev" is either the source
|
||||
* identified by the root's Error Source ID or it has an unmasked
|
||||
* error logged in its own AER Capability. Messages are emitted
|
||||
* when "ratelimit_print[i]" is non-zero. If we will print detail
|
||||
* for a downstream device, make sure we print the Error Source ID
|
||||
* from the root as well.
|
||||
*/
|
||||
if (aer_ratelimit(dev, e_info->severity)) {
|
||||
e_info->ratelimit_print[i] = 1;
|
||||
e_info->root_ratelimit_print = 1;
|
||||
}
|
||||
return -ENOSPC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -908,7 +1063,7 @@ static int find_device_iter(struct pci_dev *dev, void *data)
|
||||
* e_info->error_dev_num and e_info->dev[], based on the given information.
|
||||
*/
|
||||
static bool find_source_device(struct pci_dev *parent,
|
||||
struct aer_err_info *e_info)
|
||||
struct aer_err_info *e_info)
|
||||
{
|
||||
struct pci_dev *dev = parent;
|
||||
int result;
|
||||
@@ -926,15 +1081,8 @@ static bool find_source_device(struct pci_dev *parent,
|
||||
else
|
||||
pci_walk_bus(parent->subordinate, find_device_iter, e_info);
|
||||
|
||||
if (!e_info->error_dev_num) {
|
||||
u8 bus = e_info->id >> 8;
|
||||
u8 devfn = e_info->id & 0xff;
|
||||
|
||||
pci_info(parent, "found no error details for %04x:%02x:%02x.%d\n",
|
||||
pci_domain_nr(parent->bus), bus, PCI_SLOT(devfn),
|
||||
PCI_FUNC(devfn));
|
||||
if (!e_info->error_dev_num)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1141,9 +1289,10 @@ static void aer_recover_work_func(struct work_struct *work)
|
||||
pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus,
|
||||
entry.devfn);
|
||||
if (!pdev) {
|
||||
pr_err("no pci_dev for %04x:%02x:%02x.%x\n",
|
||||
entry.domain, entry.bus,
|
||||
PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn));
|
||||
pr_err_ratelimited("%04x:%02x:%02x.%x: no pci_dev found\n",
|
||||
entry.domain, entry.bus,
|
||||
PCI_SLOT(entry.devfn),
|
||||
PCI_FUNC(entry.devfn));
|
||||
continue;
|
||||
}
|
||||
pci_print_aer(pdev, entry.severity, entry.regs);
|
||||
@@ -1199,19 +1348,26 @@ EXPORT_SYMBOL_GPL(aer_recover_queue);
|
||||
|
||||
/**
|
||||
* aer_get_device_error_info - read error status from dev and store it to info
|
||||
* @dev: pointer to the device expected to have an error record
|
||||
* @info: pointer to structure to store the error record
|
||||
* @i: index into info->dev[]
|
||||
*
|
||||
* Return: 1 on success, 0 on error.
|
||||
*
|
||||
* Note that @info is reused among all error devices. Clear fields properly.
|
||||
*/
|
||||
int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
|
||||
int aer_get_device_error_info(struct aer_err_info *info, int i)
|
||||
{
|
||||
int type = pci_pcie_type(dev);
|
||||
int aer = dev->aer_cap;
|
||||
struct pci_dev *dev;
|
||||
int type, aer;
|
||||
u32 aercc;
|
||||
|
||||
if (i >= AER_MAX_MULTI_ERR_DEVICES)
|
||||
return 0;
|
||||
|
||||
dev = info->dev[i];
|
||||
aer = dev->aer_cap;
|
||||
type = pci_pcie_type(dev);
|
||||
|
||||
/* Must reset in this function */
|
||||
info->status = 0;
|
||||
info->tlp_header_valid = 0;
|
||||
@@ -1263,63 +1419,87 @@ static inline void aer_process_err_devices(struct aer_err_info *e_info)
|
||||
|
||||
/* Report all before handling them, to not lose records by reset etc. */
|
||||
for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) {
|
||||
if (aer_get_device_error_info(e_info->dev[i], e_info))
|
||||
aer_print_error(e_info->dev[i], e_info);
|
||||
if (aer_get_device_error_info(e_info, i))
|
||||
aer_print_error(e_info, i);
|
||||
}
|
||||
for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) {
|
||||
if (aer_get_device_error_info(e_info->dev[i], e_info))
|
||||
if (aer_get_device_error_info(e_info, i))
|
||||
handle_error_source(e_info->dev[i], e_info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* aer_isr_one_error - consume an error detected by Root Port
|
||||
* @rpc: pointer to the Root Port which holds an error
|
||||
* aer_isr_one_error_type - consume a Correctable or Uncorrectable Error
|
||||
* detected by Root Port or RCEC
|
||||
* @root: pointer to Root Port or RCEC that signaled AER interrupt
|
||||
* @info: pointer to AER error info
|
||||
*/
|
||||
static void aer_isr_one_error_type(struct pci_dev *root,
|
||||
struct aer_err_info *info)
|
||||
{
|
||||
bool found;
|
||||
|
||||
found = find_source_device(root, info);
|
||||
|
||||
/*
|
||||
* If we're going to log error messages, we've already set
|
||||
* "info->root_ratelimit_print" and "info->ratelimit_print[i]" to
|
||||
* non-zero (which enables printing) because this is either an
|
||||
* ERR_FATAL or we found a device with an error logged in its AER
|
||||
* Capability.
|
||||
*
|
||||
* If we didn't find the Error Source device, at least log the
|
||||
* Requester ID from the ERR_* Message received by the Root Port or
|
||||
* RCEC, ratelimited by the RP or RCEC.
|
||||
*/
|
||||
if (info->root_ratelimit_print ||
|
||||
(!found && aer_ratelimit(root, info->severity)))
|
||||
aer_print_source(root, info, found);
|
||||
|
||||
if (found)
|
||||
aer_process_err_devices(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* aer_isr_one_error - consume error(s) signaled by an AER interrupt from
|
||||
* Root Port or RCEC
|
||||
* @root: pointer to Root Port or RCEC that signaled AER interrupt
|
||||
* @e_src: pointer to an error source
|
||||
*/
|
||||
static void aer_isr_one_error(struct aer_rpc *rpc,
|
||||
struct aer_err_source *e_src)
|
||||
static void aer_isr_one_error(struct pci_dev *root,
|
||||
struct aer_err_source *e_src)
|
||||
{
|
||||
struct pci_dev *pdev = rpc->rpd;
|
||||
struct aer_err_info e_info;
|
||||
u32 status = e_src->status;
|
||||
|
||||
pci_rootport_aer_stats_incr(pdev, e_src);
|
||||
pci_rootport_aer_stats_incr(root, e_src);
|
||||
|
||||
/*
|
||||
* There is a possibility that both correctable error and
|
||||
* uncorrectable error being logged. Report correctable error first.
|
||||
*/
|
||||
if (e_src->status & PCI_ERR_ROOT_COR_RCV) {
|
||||
e_info.id = ERR_COR_ID(e_src->id);
|
||||
e_info.severity = AER_CORRECTABLE;
|
||||
if (status & PCI_ERR_ROOT_COR_RCV) {
|
||||
int multi = status & PCI_ERR_ROOT_MULTI_COR_RCV;
|
||||
struct aer_err_info e_info = {
|
||||
.id = ERR_COR_ID(e_src->id),
|
||||
.severity = AER_CORRECTABLE,
|
||||
.level = KERN_WARNING,
|
||||
.multi_error_valid = multi ? 1 : 0,
|
||||
};
|
||||
|
||||
if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV)
|
||||
e_info.multi_error_valid = 1;
|
||||
else
|
||||
e_info.multi_error_valid = 0;
|
||||
aer_print_port_info(pdev, &e_info);
|
||||
|
||||
if (find_source_device(pdev, &e_info))
|
||||
aer_process_err_devices(&e_info);
|
||||
aer_isr_one_error_type(root, &e_info);
|
||||
}
|
||||
|
||||
if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) {
|
||||
e_info.id = ERR_UNCOR_ID(e_src->id);
|
||||
if (status & PCI_ERR_ROOT_UNCOR_RCV) {
|
||||
int fatal = status & PCI_ERR_ROOT_FATAL_RCV;
|
||||
int multi = status & PCI_ERR_ROOT_MULTI_UNCOR_RCV;
|
||||
struct aer_err_info e_info = {
|
||||
.id = ERR_UNCOR_ID(e_src->id),
|
||||
.severity = fatal ? AER_FATAL : AER_NONFATAL,
|
||||
.level = KERN_ERR,
|
||||
.multi_error_valid = multi ? 1 : 0,
|
||||
};
|
||||
|
||||
if (e_src->status & PCI_ERR_ROOT_FATAL_RCV)
|
||||
e_info.severity = AER_FATAL;
|
||||
else
|
||||
e_info.severity = AER_NONFATAL;
|
||||
|
||||
if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV)
|
||||
e_info.multi_error_valid = 1;
|
||||
else
|
||||
e_info.multi_error_valid = 0;
|
||||
|
||||
aer_print_port_info(pdev, &e_info);
|
||||
|
||||
if (find_source_device(pdev, &e_info))
|
||||
aer_process_err_devices(&e_info);
|
||||
aer_isr_one_error_type(root, &e_info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1340,7 +1520,7 @@ static irqreturn_t aer_isr(int irq, void *context)
|
||||
return IRQ_NONE;
|
||||
|
||||
while (kfifo_get(&rpc->aer_fifo, &e_src))
|
||||
aer_isr_one_error(rpc, &e_src);
|
||||
aer_isr_one_error(rpc->rpd, &e_src);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev)
|
||||
dpc_tlp_log_len(pdev),
|
||||
pdev->subordinate->flit_mode,
|
||||
&tlp_log);
|
||||
pcie_print_tlp_log(pdev, &tlp_log, dev_fmt(""));
|
||||
pcie_print_tlp_log(pdev, &tlp_log, KERN_ERR, dev_fmt(""));
|
||||
|
||||
if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG + 1)
|
||||
goto clear_status;
|
||||
@@ -252,46 +252,59 @@ static int dpc_get_aer_uncorrect_severity(struct pci_dev *dev,
|
||||
else
|
||||
info->severity = AER_NONFATAL;
|
||||
|
||||
info->level = KERN_ERR;
|
||||
|
||||
info->dev[0] = dev;
|
||||
info->error_dev_num = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dpc_process_error(struct pci_dev *pdev)
|
||||
{
|
||||
u16 cap = pdev->dpc_cap, status, source, reason, ext_reason;
|
||||
struct aer_err_info info;
|
||||
struct aer_err_info info = {};
|
||||
|
||||
pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status);
|
||||
pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID, &source);
|
||||
|
||||
pci_info(pdev, "containment event, status:%#06x source:%#06x\n",
|
||||
status, source);
|
||||
|
||||
reason = status & PCI_EXP_DPC_STATUS_TRIGGER_RSN;
|
||||
ext_reason = status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT;
|
||||
pci_warn(pdev, "%s detected\n",
|
||||
(reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_UNCOR) ?
|
||||
"unmasked uncorrectable error" :
|
||||
(reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_NFE) ?
|
||||
"ERR_NONFATAL" :
|
||||
(reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE) ?
|
||||
"ERR_FATAL" :
|
||||
(ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO) ?
|
||||
"RP PIO error" :
|
||||
(ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_SW_TRIGGER) ?
|
||||
"software trigger" :
|
||||
"reserved error");
|
||||
|
||||
/* show RP PIO error detail information */
|
||||
if (pdev->dpc_rp_extensions &&
|
||||
reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_IN_EXT &&
|
||||
ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO)
|
||||
dpc_process_rp_pio_error(pdev);
|
||||
else if (reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_UNCOR &&
|
||||
dpc_get_aer_uncorrect_severity(pdev, &info) &&
|
||||
aer_get_device_error_info(pdev, &info)) {
|
||||
aer_print_error(pdev, &info);
|
||||
pci_aer_clear_nonfatal_status(pdev);
|
||||
pci_aer_clear_fatal_status(pdev);
|
||||
switch (reason) {
|
||||
case PCI_EXP_DPC_STATUS_TRIGGER_RSN_UNCOR:
|
||||
pci_warn(pdev, "containment event, status:%#06x: unmasked uncorrectable error detected\n",
|
||||
status);
|
||||
if (dpc_get_aer_uncorrect_severity(pdev, &info) &&
|
||||
aer_get_device_error_info(&info, 0)) {
|
||||
aer_print_error(&info, 0);
|
||||
pci_aer_clear_nonfatal_status(pdev);
|
||||
pci_aer_clear_fatal_status(pdev);
|
||||
}
|
||||
break;
|
||||
case PCI_EXP_DPC_STATUS_TRIGGER_RSN_NFE:
|
||||
case PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE:
|
||||
pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID,
|
||||
&source);
|
||||
pci_warn(pdev, "containment event, status:%#06x, %s received from %04x:%02x:%02x.%d\n",
|
||||
status,
|
||||
(reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE) ?
|
||||
"ERR_FATAL" : "ERR_NONFATAL",
|
||||
pci_domain_nr(pdev->bus), PCI_BUS_NUM(source),
|
||||
PCI_SLOT(source), PCI_FUNC(source));
|
||||
break;
|
||||
case PCI_EXP_DPC_STATUS_TRIGGER_RSN_IN_EXT:
|
||||
ext_reason = status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT;
|
||||
pci_warn(pdev, "containment event, status:%#06x: %s detected\n",
|
||||
status,
|
||||
(ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO) ?
|
||||
"RP PIO error" :
|
||||
(ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_SW_TRIGGER) ?
|
||||
"software trigger" :
|
||||
"reserved error");
|
||||
/* show RP PIO error detail information */
|
||||
if (ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO &&
|
||||
pdev->dpc_rp_extensions)
|
||||
dpc_process_rp_pio_error(pdev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -271,7 +271,6 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
|
||||
|
||||
pci_uevent_ers(bridge, PCI_ERS_RESULT_DISCONNECT);
|
||||
|
||||
/* TODO: Should kernel panic here? */
|
||||
pci_info(bridge, "device recovery failed\n");
|
||||
|
||||
return status;
|
||||
|
||||
@@ -98,12 +98,14 @@ int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2,
|
||||
* pcie_print_tlp_log - Print TLP Header / Prefix Log contents
|
||||
* @dev: PCIe device
|
||||
* @log: TLP Log structure
|
||||
* @level: Printk log level
|
||||
* @pfx: String prefix
|
||||
*
|
||||
* Prints TLP Header and Prefix Log information held by @log.
|
||||
*/
|
||||
void pcie_print_tlp_log(const struct pci_dev *dev,
|
||||
const struct pcie_tlp_log *log, const char *pfx)
|
||||
const struct pcie_tlp_log *log, const char *level,
|
||||
const char *pfx)
|
||||
{
|
||||
/* EE_PREFIX_STR fits the extended DW space needed for the Flit mode */
|
||||
char buf[11 * PCIE_STD_MAX_TLP_HEADERLOG + 1];
|
||||
@@ -130,6 +132,6 @@ void pcie_print_tlp_log(const struct pci_dev *dev,
|
||||
}
|
||||
}
|
||||
|
||||
pci_err(dev, "%sTLP Header%s: %s\n", pfx,
|
||||
dev_printk(level, &dev->dev, "%sTLP Header%s: %s\n", pfx,
|
||||
log->flit ? " (Flit)" : "", buf);
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ struct pci_dev {
|
||||
u8 hdr_type; /* PCI header type (`multi' flag masked out) */
|
||||
#ifdef CONFIG_PCIEAER
|
||||
u16 aer_cap; /* AER capability offset */
|
||||
struct aer_stats *aer_stats; /* AER stats for this device */
|
||||
struct aer_info *aer_info; /* AER info for this device */
|
||||
#endif
|
||||
#ifdef CONFIG_PCIEPORTBUS
|
||||
struct rcec_ea *rcec_ea; /* RCEC cached endpoint association */
|
||||
|
||||
Reference in New Issue
Block a user