PCI/AER: Save AER Capability for suspend/resume

Previously we did not save and restore the AER configuration on
suspend/resume, so the configuration may be lost after resume.

Save the AER configuration during suspend and restore it during resume.

[bhelgaas: commit log]
Link: https://lore.kernel.org/r/92EBB4272BF81E4089A7126EC1E7B28492C3B007@IRSMSX101.ger.corp.intel.com
Signed-off-by: Mayurkumar Patel <mayurkumar.patel@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
This commit is contained in:
Patel, Mayurkumar 2019-10-18 16:52:21 +00:00 committed by Bjorn Helgaas
parent 54ecb8f702
commit af65d1ad41
5 changed files with 69 additions and 4 deletions

View File

@ -355,7 +355,7 @@ static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev)
pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT; pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT;
} }
static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev) bool pcie_cap_has_rtctl(const struct pci_dev *dev)
{ {
int type = pci_pcie_type(dev); int type = pci_pcie_type(dev);

View File

@ -1361,6 +1361,7 @@ int pci_save_state(struct pci_dev *dev)
pci_save_ltr_state(dev); pci_save_ltr_state(dev);
pci_save_dpc_state(dev); pci_save_dpc_state(dev);
pci_save_aer_state(dev);
return pci_save_vc_state(dev); return pci_save_vc_state(dev);
} }
EXPORT_SYMBOL(pci_save_state); EXPORT_SYMBOL(pci_save_state);
@ -1474,6 +1475,7 @@ void pci_restore_state(struct pci_dev *dev)
pci_restore_dpc_state(dev); pci_restore_dpc_state(dev);
pci_cleanup_aer_error_status_regs(dev); pci_cleanup_aer_error_status_regs(dev);
pci_restore_aer_state(dev);
pci_restore_config_space(dev); pci_restore_config_space(dev);

View File

@ -12,6 +12,7 @@ extern const unsigned char pcie_link_speed[];
extern bool pci_early_dump; extern bool pci_early_dump;
bool pcie_cap_has_lnkctl(const struct pci_dev *dev); bool pcie_cap_has_lnkctl(const struct pci_dev *dev);
bool pcie_cap_has_rtctl(const struct pci_dev *dev);
/* Functions internal to the PCI core code */ /* Functions internal to the PCI core code */

View File

@ -448,12 +448,70 @@ int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
return 0; return 0;
} }
void pci_save_aer_state(struct pci_dev *dev)
{
struct pci_cap_saved_state *save_state;
u32 *cap;
int pos;
pos = dev->aer_cap;
if (!pos)
return;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_ERR);
if (!save_state)
return;
cap = &save_state->cap.data[0];
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, cap++);
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, cap++);
pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, cap++);
pci_read_config_dword(dev, pos + PCI_ERR_CAP, cap++);
if (pcie_cap_has_rtctl(dev))
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, cap++);
}
void pci_restore_aer_state(struct pci_dev *dev)
{
struct pci_cap_saved_state *save_state;
u32 *cap;
int pos;
pos = dev->aer_cap;
if (!pos)
return;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_ERR);
if (!save_state)
return;
cap = &save_state->cap.data[0];
pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, *cap++);
pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, *cap++);
pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, *cap++);
pci_write_config_dword(dev, pos + PCI_ERR_CAP, *cap++);
if (pcie_cap_has_rtctl(dev))
pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, *cap++);
}
void pci_aer_init(struct pci_dev *dev) void pci_aer_init(struct pci_dev *dev)
{ {
dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); int n;
if (dev->aer_cap) dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL); if (!dev->aer_cap)
return;
dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL);
/*
* We save/restore PCI_ERR_UNCOR_MASK, PCI_ERR_UNCOR_SEVER,
* PCI_ERR_COR_MASK, and PCI_ERR_CAP. Root and Root Complex Event
* Collectors also implement PCI_ERR_ROOT_COMMAND (PCIe r5.0, sec
* 7.8.4).
*/
n = pcie_cap_has_rtctl(dev) ? 5 : 4;
pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_ERR, sizeof(u32) * n);
pci_cleanup_aer_error_status_regs(dev); pci_cleanup_aer_error_status_regs(dev);
} }

View File

@ -46,6 +46,8 @@ 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); int pci_cleanup_aer_error_status_regs(struct pci_dev *dev);
void pci_save_aer_state(struct pci_dev *dev);
void pci_restore_aer_state(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)
{ {
@ -63,6 +65,8 @@ static inline int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
{ {
return -EINVAL; return -EINVAL;
} }
static inline void pci_save_aer_state(struct pci_dev *dev) {}
static inline void pci_restore_aer_state(struct pci_dev *dev) {}
#endif #endif
void cper_print_aer(struct pci_dev *dev, int aer_severity, void cper_print_aer(struct pci_dev *dev, int aer_severity,