Commit 3d4036cb authored by Taku Izumi's avatar Taku Izumi Committed by Jiri Slaby

PCI/AER: Clear error status registers during enumeration and restore

commit b07461a8 upstream.

AER errors might be recorded when powering-on devices.  These errors can be
ignored, so firmware usually clears them before the OS enumerates devices.
However, firmware is not involved when devices are added via hotplug, so
the OS may discover power-up errors that should be ignored.  The same may
happen when powering up devices when resuming after suspend.

Clear the AER error status registers during enumeration and resume.

[bhelgaas: changelog, remove repetitive comments]
Signed-off-by: default avatarTaku Izumi <izumi.taku@jp.fujitsu.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
parent 1f3d0f52
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/pci_hotplug.h> #include <linux/pci_hotplug.h>
#include <asm-generic/pci-bridge.h> #include <asm-generic/pci-bridge.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <linux/aer.h>
#include "pci.h" #include "pci.h"
const char *pci_power_names[] = { const char *pci_power_names[] = {
...@@ -1005,6 +1006,8 @@ void pci_restore_state(struct pci_dev *dev) ...@@ -1005,6 +1006,8 @@ void pci_restore_state(struct pci_dev *dev)
pci_restore_pcie_state(dev); pci_restore_pcie_state(dev);
pci_restore_ats_state(dev); pci_restore_ats_state(dev);
pci_cleanup_aer_error_status_regs(dev);
pci_restore_config_space(dev); pci_restore_config_space(dev);
pci_restore_pcix_state(dev); pci_restore_pcix_state(dev);
......
...@@ -74,6 +74,34 @@ int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) ...@@ -74,6 +74,34 @@ int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
} }
EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status); EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
{
int pos;
u32 status;
int port_type;
if (!pci_is_pcie(dev))
return -ENODEV;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos)
return -EIO;
port_type = pci_pcie_type(dev);
if (port_type == PCI_EXP_TYPE_ROOT_PORT) {
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status);
}
pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status);
pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, status);
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
return 0;
}
/** /**
* add_error_device - list device to be handled * add_error_device - list device to be handled
* @e_info: pointer to error info * @e_info: pointer to error info
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/pci-aspm.h> #include <linux/pci-aspm.h>
#include <linux/aer.h>
#include <asm-generic/pci-bridge.h> #include <asm-generic/pci-bridge.h>
#include "pci.h" #include "pci.h"
...@@ -1356,6 +1357,8 @@ static void pci_init_capabilities(struct pci_dev *dev) ...@@ -1356,6 +1357,8 @@ static void pci_init_capabilities(struct pci_dev *dev)
/* Enable ACS P2P upstream forwarding */ /* Enable ACS P2P upstream forwarding */
pci_enable_acs(dev); pci_enable_acs(dev);
pci_cleanup_aer_error_status_regs(dev);
} }
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
......
...@@ -38,6 +38,7 @@ struct aer_capability_regs { ...@@ -38,6 +38,7 @@ struct aer_capability_regs {
int pci_enable_pcie_error_reporting(struct pci_dev *dev); int pci_enable_pcie_error_reporting(struct pci_dev *dev);
int pci_disable_pcie_error_reporting(struct pci_dev *dev); int pci_disable_pcie_error_reporting(struct pci_dev *dev);
int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev); int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
int pci_cleanup_aer_error_status_regs(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)
{ {
...@@ -51,6 +52,10 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) ...@@ -51,6 +52,10 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
{ {
return -EINVAL; return -EINVAL;
} }
static inline int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
{
return -EINVAL;
}
#endif #endif
void cper_print_aer(struct pci_dev *dev, int cper_severity, void cper_print_aer(struct pci_dev *dev, int cper_severity,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment