Merge branch 'pci/betty-aer-v3' into next

* pci/betty-aer-v3:
  PCI/AER: Reset link for devices below Root Port or Downstream Port
  ACPI / APEI: Force fatal AER severity when component has been reset
  PCI/AER: Remove "extern" from function declarations
  PCI/AER: Move AER severity defines to aer.h
  PCI/AER: Set dev->__aer_firmware_first only for matching devices
  PCI/AER: Factor out HEST device type matching
  PCI/AER: Don't parse HEST table for non-PCIe devices
This commit is contained in:
Bjorn Helgaas 2013-06-07 14:24:00 -06:00
commit 5899309c90
5 changed files with 55 additions and 43 deletions

View file

@ -449,9 +449,19 @@ static void ghes_do_proc(struct ghes *ghes,
pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
unsigned int devfn; unsigned int devfn;
int aer_severity; int aer_severity;
devfn = PCI_DEVFN(pcie_err->device_id.device, devfn = PCI_DEVFN(pcie_err->device_id.device,
pcie_err->device_id.function); pcie_err->device_id.function);
aer_severity = cper_severity_to_aer(sev); aer_severity = cper_severity_to_aer(sev);
/*
* If firmware reset the component to contain
* the error, we must reinitialize it before
* use, so treat it as a fatal AER error.
*/
if (gdata->flags & CPER_SEC_RESET)
aer_severity = AER_FATAL;
aer_recover_queue(pcie_err->device_id.segment, aer_recover_queue(pcie_err->device_id.segment,
pcie_err->device_id.bus, pcie_err->device_id.bus,
devfn, aer_severity); devfn, aer_severity);

View file

@ -13,10 +13,6 @@
#include <linux/aer.h> #include <linux/aer.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#define AER_NONFATAL 0
#define AER_FATAL 1
#define AER_CORRECTABLE 2
#define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \ #define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \
PCI_EXP_RTCTL_SENFEE| \ PCI_EXP_RTCTL_SENFEE| \
PCI_EXP_RTCTL_SEFEE) PCI_EXP_RTCTL_SEFEE)

View file

@ -29,6 +29,22 @@ static inline int hest_match_pci(struct acpi_hest_aer_common *p,
p->function == PCI_FUNC(pci->devfn)); p->function == PCI_FUNC(pci->devfn));
} }
static inline bool hest_match_type(struct acpi_hest_header *hest_hdr,
struct pci_dev *dev)
{
u16 hest_type = hest_hdr->type;
u8 pcie_type = pci_pcie_type(dev);
if ((hest_type == ACPI_HEST_TYPE_AER_ROOT_PORT &&
pcie_type == PCI_EXP_TYPE_ROOT_PORT) ||
(hest_type == ACPI_HEST_TYPE_AER_ENDPOINT &&
pcie_type == PCI_EXP_TYPE_ENDPOINT) ||
(hest_type == ACPI_HEST_TYPE_AER_BRIDGE &&
(dev->class >> 16) == PCI_BASE_CLASS_BRIDGE))
return true;
return false;
}
struct aer_hest_parse_info { struct aer_hest_parse_info {
struct pci_dev *pci_dev; struct pci_dev *pci_dev;
int firmware_first; int firmware_first;
@ -38,34 +54,16 @@ static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data)
{ {
struct aer_hest_parse_info *info = data; struct aer_hest_parse_info *info = data;
struct acpi_hest_aer_common *p; struct acpi_hest_aer_common *p;
u8 pcie_type = 0; int ff;
u8 bridge = 0;
int ff = 0;
switch (hest_hdr->type) {
case ACPI_HEST_TYPE_AER_ROOT_PORT:
pcie_type = PCI_EXP_TYPE_ROOT_PORT;
break;
case ACPI_HEST_TYPE_AER_ENDPOINT:
pcie_type = PCI_EXP_TYPE_ENDPOINT;
break;
case ACPI_HEST_TYPE_AER_BRIDGE:
if ((info->pci_dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
bridge = 1;
break;
default:
return 0;
}
p = (struct acpi_hest_aer_common *)(hest_hdr + 1); p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
if (p->flags & ACPI_HEST_GLOBAL) { if (p->flags & ACPI_HEST_GLOBAL) {
if ((pci_is_pcie(info->pci_dev) && if (hest_match_type(hest_hdr, info->pci_dev))
pci_pcie_type(info->pci_dev) == pcie_type) || bridge) info->firmware_first = ff;
ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
} else } else
if (hest_match_pci(p, info->pci_dev)) if (hest_match_pci(p, info->pci_dev))
ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); info->firmware_first = ff;
info->firmware_first = ff;
return 0; return 0;
} }
@ -89,6 +87,9 @@ static void aer_set_firmware_first(struct pci_dev *pci_dev)
int pcie_aer_get_firmware_first(struct pci_dev *dev) int pcie_aer_get_firmware_first(struct pci_dev *dev)
{ {
if (!pci_is_pcie(dev))
return 0;
if (!dev->__aer_firmware_first_valid) if (!dev->__aer_firmware_first_valid)
aer_set_firmware_first(dev); aer_set_firmware_first(dev);
return dev->__aer_firmware_first; return dev->__aer_firmware_first;

View file

@ -400,16 +400,16 @@ void aer_do_secondary_bus_reset(struct pci_dev *dev)
} }
/** /**
* default_downstream_reset_link - default reset function for Downstream Port * default_reset_link - default reset function
* @dev: pointer to downstream port's pci_dev data structure * @dev: pointer to pci_dev data structure
* *
* Invoked when performing link reset at Downstream Port w/ no aer driver. * Invoked when performing link reset on a Downstream Port or a
* Root Port with no aer driver.
*/ */
static pci_ers_result_t default_downstream_reset_link(struct pci_dev *dev) static pci_ers_result_t default_reset_link(struct pci_dev *dev)
{ {
aer_do_secondary_bus_reset(dev); aer_do_secondary_bus_reset(dev);
dev_printk(KERN_DEBUG, &dev->dev, dev_printk(KERN_DEBUG, &dev->dev, "downstream link has been reset\n");
"Downstream Port link has been reset\n");
return PCI_ERS_RESULT_RECOVERED; return PCI_ERS_RESULT_RECOVERED;
} }
@ -458,8 +458,9 @@ static pci_ers_result_t reset_link(struct pci_dev *dev)
if (driver && driver->reset_link) { if (driver && driver->reset_link) {
status = driver->reset_link(udev); status = driver->reset_link(udev);
} else if (pci_pcie_type(udev) == PCI_EXP_TYPE_DOWNSTREAM) { } else if (pci_pcie_type(udev) == PCI_EXP_TYPE_DOWNSTREAM ||
status = default_downstream_reset_link(udev); pci_pcie_type(udev) == PCI_EXP_TYPE_ROOT_PORT) {
status = default_reset_link(udev);
} else { } else {
dev_printk(KERN_DEBUG, &dev->dev, dev_printk(KERN_DEBUG, &dev->dev,
"no link-reset support at upstream device %s\n", "no link-reset support at upstream device %s\n",

View file

@ -7,6 +7,10 @@
#ifndef _AER_H_ #ifndef _AER_H_
#define _AER_H_ #define _AER_H_
#define AER_NONFATAL 0
#define AER_FATAL 1
#define AER_CORRECTABLE 2
struct aer_header_log_regs { struct aer_header_log_regs {
unsigned int dw0; unsigned int dw0;
unsigned int dw1; unsigned int dw1;
@ -31,9 +35,9 @@ struct aer_capability_regs {
#if defined(CONFIG_PCIEAER) #if defined(CONFIG_PCIEAER)
/* pci-e port driver needs this function to enable aer */ /* pci-e port driver needs this function to enable aer */
extern int pci_enable_pcie_error_reporting(struct pci_dev *dev); int pci_enable_pcie_error_reporting(struct pci_dev *dev);
extern int pci_disable_pcie_error_reporting(struct pci_dev *dev); int pci_disable_pcie_error_reporting(struct pci_dev *dev);
extern int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev); int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
#else #else
static inline int pci_enable_pcie_error_reporting(struct pci_dev *dev) static inline int pci_enable_pcie_error_reporting(struct pci_dev *dev)
{ {
@ -49,10 +53,10 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
} }
#endif #endif
extern void cper_print_aer(const char *prefix, struct pci_dev *dev, void cper_print_aer(const char *prefix, struct pci_dev *dev, int cper_severity,
int cper_severity, struct aer_capability_regs *aer); struct aer_capability_regs *aer);
extern int cper_severity_to_aer(int cper_severity); int cper_severity_to_aer(int cper_severity);
extern void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
int severity); int severity);
#endif //_AER_H_ #endif //_AER_H_