summarylogtreecommitdiffstats
path: root/0001-restore-pci-bridge-configuration-space-on-bridge-reset.patch
blob: 3048cdbb546edceb0b80dd67d4dd9b9dbdb315d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
diff -bur archlinux-linux/drivers/pci/pci.c archlinux-linux/drivers/pci/pci.c
--- archlinux-linux/drivers/pci/pci.c	2018-11-03 11:22:52.203892151 -0700
+++ archlinux-linux/drivers/pci/pci.c	2018-11-03 11:24:11.346388035 -0700
@@ -1160,13 +1160,13 @@
 					 retry, force);
 }
 
-static void pci_restore_config_space(struct pci_dev *pdev)
+static void pci_restore_config_space(struct pci_dev *pdev, bool force)
 {
 	if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
-		pci_restore_config_space_range(pdev, 10, 15, 0, false);
+		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, false);
-		pci_restore_config_space_range(pdev, 0, 3, 0, false);
+		pci_restore_config_space_range(pdev, 4, 9, 10, force);
+		pci_restore_config_space_range(pdev, 0, 3, 0, force);
 	} else if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
 		pci_restore_config_space_range(pdev, 12, 15, 0, false);
 
@@ -1178,7 +1178,7 @@
 		pci_restore_config_space_range(pdev, 9, 11, 0, true);
 		pci_restore_config_space_range(pdev, 0, 8, 0, false);
 	} else {
-		pci_restore_config_space_range(pdev, 0, 15, 0, false);
+		pci_restore_config_space_range(pdev, 0, 15, 0, force);
 	}
 }
 
@@ -1209,11 +1209,7 @@
 	}
 }
 
-/**
- * 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)
+void _pci_restore_state(struct pci_dev *dev, bool force)
 {
 	if (!dev->state_saved)
 		return;
@@ -1228,7 +1224,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);
@@ -1239,6 +1235,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 {
@@ -4272,6 +4277,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);
@@ -4282,10 +4289,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 archlinux-linux/include/linux/pci.h archlinux-linux/include/linux/pci.h
--- archlinux-linux/include/linux/pci.h	2018-11-03 11:22:52.207225588 -0700
+++ archlinux-linux/include/linux/pci.h	2018-11-03 11:27:18.255617475 -0700
@@ -1640,7 +1640,7 @@
 
 /* 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) { }
+static inline void _pci_restore_state(struct pci_dev *dev, bool 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)