summarylogtreecommitdiffstats
path: root/0003-restore-pci-bridge-configuration-space-on-bridge-reset.patch
diff options
context:
space:
mode:
Diffstat (limited to '0003-restore-pci-bridge-configuration-space-on-bridge-reset.patch')
-rw-r--r--0003-restore-pci-bridge-configuration-space-on-bridge-reset.patch131
1 files changed, 131 insertions, 0 deletions
diff --git a/0003-restore-pci-bridge-configuration-space-on-bridge-reset.patch b/0003-restore-pci-bridge-configuration-space-on-bridge-reset.patch
new file mode 100644
index 000000000000..2ef9f28ced17
--- /dev/null
+++ b/0003-restore-pci-bridge-configuration-space-on-bridge-reset.patch
@@ -0,0 +1,131 @@
+diff -bur linux-4.15-patched/drivers/pci/pci.c linux-4.15/drivers/pci/pci.c
+--- linux-4.15-patched/drivers/pci/pci.c 2018-03-04 21:12:43.927969009 -0800
++++ linux-4.15/drivers/pci/pci.c 2018-03-04 21:20:14.972944154 -0800
+@@ -1112,12 +1112,12 @@
+ EXPORT_SYMBOL(pci_save_state);
+
+ static void pci_restore_config_dword(struct pci_dev *pdev, int offset,
+- u32 saved_val, int retry)
++ u32 saved_val, int retry, int force)
+ {
+ u32 val;
+
+ pci_read_config_dword(pdev, offset, &val);
+- if (val == saved_val)
++ if (!force && val == saved_val)
+ return;
+
+ for (;;) {
+@@ -1136,33 +1136,29 @@
+ }
+
+ static void pci_restore_config_space_range(struct pci_dev *pdev,
+- int start, int end, int retry)
++ int start, int end, int retry, int force)
+ {
+ int index;
+
+ for (index = end; index >= start; index--)
+ pci_restore_config_dword(pdev, 4 * index,
+ pdev->saved_config_space[index],
+- retry);
++ retry, force);
+ }
+
+-static void pci_restore_config_space(struct pci_dev *pdev)
++static void pci_restore_config_space(struct pci_dev *pdev, int force)
+ {
+ if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
+- pci_restore_config_space_range(pdev, 10, 15, 0);
++ pci_restore_config_space_range(pdev, 10, 15, 0, force);
+ /* Restore BARs before the command register. */
+- pci_restore_config_space_range(pdev, 4, 9, 10);
+- pci_restore_config_space_range(pdev, 0, 3, 0);
++ pci_restore_config_space_range(pdev, 4, 9, 10, force);
++ pci_restore_config_space_range(pdev, 0, 3, 0, force);
+ } else {
+- pci_restore_config_space_range(pdev, 0, 15, 0);
++ pci_restore_config_space_range(pdev, 0, 15, 0, force);
+ }
+ }
+
+-/**
+- * pci_restore_state - Restore the saved state of a PCI device
+- * @dev: - PCI device that we're dealing with
+- */
+-void pci_restore_state(struct pci_dev *dev)
++static void _pci_restore_state(struct pci_dev *dev, int force)
+ {
+ if (!dev->state_saved)
+ return;
+@@ -1176,7 +1172,7 @@
+
+ pci_cleanup_aer_error_status_regs(dev);
+
+- pci_restore_config_space(dev);
++ pci_restore_config_space(dev, force);
+
+ pci_restore_pcix_state(dev);
+ pci_restore_msi_state(dev);
+@@ -1187,6 +1183,15 @@
+
+ dev->state_saved = false;
+ }
++
++/**
++ * pci_restore_state - Restore the saved state of a PCI device
++ * @dev: - PCI device that we're dealing with
++ */
++void pci_restore_state(struct pci_dev *dev)
++{
++ _pci_restore_state(dev, 0);
++}
+ EXPORT_SYMBOL(pci_restore_state);
+
+ struct pci_saved_state {
+@@ -4083,6 +4088,8 @@
+ {
+ u16 ctrl;
+
++ pci_save_state(dev);
++
+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
+ ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+@@ -4092,10 +4099,23 @@
+ */
+ msleep(2);
+
++ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
+ ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+
+ /*
++ * According to PCI-to-PCI Bridge Architecture Specification 3.2.5.17
++ *
++ * "The bridge’s secondary bus interface and any buffers between
++ * the two interfaces (primary and secondary) must be initialized
++ * back to their default state whenever this bit is set."
++ *
++ * Failure to observe this causes inability to access devices on the
++ * secondary bus on the AMD Threadripper platform.
++ */
++ _pci_restore_state(dev, 1);
++
++ /*
+ * Trhfa for conventional PCI is 2^25 clock cycles.
+ * Assuming a minimum 33MHz clock this results in a 1s
+ * delay before we can consider subordinate devices to
+diff -bur linux-4.15-patched/include/linux/pci.h linux-4.15/include/linux/pci.h
+--- linux-4.15-patched/include/linux/pci.h 2018-03-04 21:12:43.808969015 -0800
++++ linux-4.15/include/linux/pci.h 2018-03-04 21:28:17.950917540 -0800
+@@ -1640,7 +1640,8 @@
+
+ /* Power management related routines */
+ static inline int pci_save_state(struct pci_dev *dev) { return 0; }
+-static inline void pci_restore_state(struct pci_dev *dev) { }
++void pci_restore_state(struct pci_dev *dev) { }
++static inline void _pci_restore_state(struct pci_dev *dev, int force) { }
+ static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+ { return 0; }
+ static inline int pci_wake_from_d3(struct pci_dev *dev, bool enable)