PCI/AER: Save AER Capability for suspend/resume
authorPatel, Mayurkumar <mayurkumar.patel@intel.com>
Fri, 18 Oct 2019 16:52:21 +0000 (16:52 +0000)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 18 Oct 2019 22:05:42 +0000 (17:05 -0500)
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>
drivers/pci/access.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer.c
include/linux/aer.h

index 2fccb57..79c4a2e 100644 (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;
 }
 
-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);
 
index e7982af..d026365 100644 (file)
@@ -1361,6 +1361,7 @@ int pci_save_state(struct pci_dev *dev)
 
        pci_save_ltr_state(dev);
        pci_save_dpc_state(dev);
+       pci_save_aer_state(dev);
        return pci_save_vc_state(dev);
 }
 EXPORT_SYMBOL(pci_save_state);
@@ -1474,6 +1475,7 @@ void pci_restore_state(struct pci_dev *dev)
        pci_restore_dpc_state(dev);
 
        pci_cleanup_aer_error_status_regs(dev);
+       pci_restore_aer_state(dev);
 
        pci_restore_config_space(dev);
 
index 3f6947e..b96988f 100644 (file)
@@ -12,6 +12,7 @@ extern const unsigned char pcie_link_speed[];
 extern bool pci_early_dump;
 
 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 */
 
index b45bc47..4435128 100644 (file)
@@ -448,12 +448,70 @@ int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
        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)
 {
+       int n;
+
        dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+       if (!dev->aer_cap)
+               return;
 
-       if (dev->aer_cap)
-               dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL);
+       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);
 }
index 514bffa..fa19e01 100644 (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_cleanup_aer_uncorrect_error_status(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
 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;
 }
+static inline void pci_save_aer_state(struct pci_dev *dev) {}
+static inline void pci_restore_aer_state(struct pci_dev *dev) {}
 #endif
 
 void cper_print_aer(struct pci_dev *dev, int aer_severity,