diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2018-01-31 11:10:28 -0500 |
---|---|---|
committer | Bjorn Helgaas <helgaas@kernel.org> | 2018-01-31 11:10:28 -0500 |
commit | 3972b0e2c2abd027286b276fd07b7eea64cb7469 (patch) | |
tree | 1d77993832fecfd52a0b160d4e23e2a18819d5d4 | |
parent | ac7ab8a6b34f1403eab64749ce400b228c17af53 (diff) | |
parent | 65d5e9135f3b0281b97f1749d10dcfc7233e65ab (diff) |
Merge branch 'pci/dpc' into next
* pci/dpc:
PCI/DPC: Reformat DPC register definitions
PCI/DPC: Add and use DPC Status register field definitions
PCI/DPC: Squash dpc_rp_pio_get_info() into dpc_process_rp_pio_error()
PCI/DPC: Remove unnecessary RP PIO register structs
PCI/DPC: Push dpc->rp_pio_status assignment into dpc_rp_pio_get_info()
PCI/DPC: Squash dpc_rp_pio_print_error() into dpc_rp_pio_get_info()
PCI/DPC: Make RP PIO log size check more generic
PCI/DPC: Rename local "status" to "dpc_status"
PCI/DPC: Squash dpc_rp_pio_print_tlp_header() into dpc_rp_pio_print_error()
PCI/DPC: Process RP PIO details only if RP PIO extensions supported
PCI/DPC: Read RP PIO Log Size once at probe
PCI/DPC: Rename struct dpc_dev.rp to rp_extensions
PCI/DPC: Add local variable for DPC capability offset
PCI/DPC: Rename interrupt_event_handler() to dpc_work()
PCI/DPC: Fix interrupt message number print
PCI/DPC: Enable DPC only if AER is available
PCI/DPC: Fix shared interrupt handling
-rw-r--r-- | drivers/pci/pcie/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/pcie-dpc.c | 251 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 4 | ||||
-rw-r--r-- | include/uapi/linux/pci_regs.h | 24 |
4 files changed, 122 insertions, 159 deletions
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index ac53edbc9613..d658dfa53b87 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig | |||
@@ -92,7 +92,7 @@ config PCIE_PME | |||
92 | 92 | ||
93 | config PCIE_DPC | 93 | config PCIE_DPC |
94 | bool "PCIe Downstream Port Containment support" | 94 | bool "PCIe Downstream Port Containment support" |
95 | depends on PCIEPORTBUS | 95 | depends on PCIEPORTBUS && PCIEAER |
96 | default n | 96 | default n |
97 | help | 97 | help |
98 | This enables PCI Express Downstream Port Containment (DPC) | 98 | This enables PCI Express Downstream Port Containment (DPC) |
diff --git a/drivers/pci/pcie/pcie-dpc.c b/drivers/pci/pcie/pcie-dpc.c index 2d976a623ddc..7eb9bc7d4bfd 100644 --- a/drivers/pci/pcie/pcie-dpc.c +++ b/drivers/pci/pcie/pcie-dpc.c | |||
@@ -15,34 +15,15 @@ | |||
15 | #include <linux/pci.h> | 15 | #include <linux/pci.h> |
16 | #include <linux/pcieport_if.h> | 16 | #include <linux/pcieport_if.h> |
17 | #include "../pci.h" | 17 | #include "../pci.h" |
18 | 18 | #include "aer/aerdrv.h" | |
19 | struct rp_pio_header_log_regs { | ||
20 | u32 dw0; | ||
21 | u32 dw1; | ||
22 | u32 dw2; | ||
23 | u32 dw3; | ||
24 | }; | ||
25 | |||
26 | struct dpc_rp_pio_regs { | ||
27 | u32 status; | ||
28 | u32 mask; | ||
29 | u32 severity; | ||
30 | u32 syserror; | ||
31 | u32 exception; | ||
32 | |||
33 | struct rp_pio_header_log_regs header_log; | ||
34 | u32 impspec_log; | ||
35 | u32 tlp_prefix_log[4]; | ||
36 | u32 log_size; | ||
37 | u16 first_error; | ||
38 | }; | ||
39 | 19 | ||
40 | struct dpc_dev { | 20 | struct dpc_dev { |
41 | struct pcie_device *dev; | 21 | struct pcie_device *dev; |
42 | struct work_struct work; | 22 | struct work_struct work; |
43 | int cap_pos; | 23 | u16 cap_pos; |
44 | bool rp; | 24 | bool rp_extensions; |
45 | u32 rp_pio_status; | 25 | u32 rp_pio_status; |
26 | u8 rp_log_size; | ||
46 | }; | 27 | }; |
47 | 28 | ||
48 | static const char * const rp_pio_error_string[] = { | 29 | static const char * const rp_pio_error_string[] = { |
@@ -72,13 +53,13 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc) | |||
72 | unsigned long timeout = jiffies + HZ; | 53 | unsigned long timeout = jiffies + HZ; |
73 | struct pci_dev *pdev = dpc->dev->port; | 54 | struct pci_dev *pdev = dpc->dev->port; |
74 | struct device *dev = &dpc->dev->device; | 55 | struct device *dev = &dpc->dev->device; |
75 | u16 status; | 56 | u16 cap = dpc->cap_pos, status; |
76 | 57 | ||
77 | pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status); | 58 | pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status); |
78 | while (status & PCI_EXP_DPC_RP_BUSY && | 59 | while (status & PCI_EXP_DPC_RP_BUSY && |
79 | !time_after(jiffies, timeout)) { | 60 | !time_after(jiffies, timeout)) { |
80 | msleep(10); | 61 | msleep(10); |
81 | pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status); | 62 | pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status); |
82 | } | 63 | } |
83 | if (status & PCI_EXP_DPC_RP_BUSY) { | 64 | if (status & PCI_EXP_DPC_RP_BUSY) { |
84 | dev_warn(dev, "DPC root port still busy\n"); | 65 | dev_warn(dev, "DPC root port still busy\n"); |
@@ -104,11 +85,12 @@ static void dpc_wait_link_inactive(struct dpc_dev *dpc) | |||
104 | dev_warn(dev, "Link state not disabled for DPC event\n"); | 85 | dev_warn(dev, "Link state not disabled for DPC event\n"); |
105 | } | 86 | } |
106 | 87 | ||
107 | static void interrupt_event_handler(struct work_struct *work) | 88 | static void dpc_work(struct work_struct *work) |
108 | { | 89 | { |
109 | struct dpc_dev *dpc = container_of(work, struct dpc_dev, work); | 90 | struct dpc_dev *dpc = container_of(work, struct dpc_dev, work); |
110 | struct pci_dev *dev, *temp, *pdev = dpc->dev->port; | 91 | struct pci_dev *dev, *temp, *pdev = dpc->dev->port; |
111 | struct pci_bus *parent = pdev->subordinate; | 92 | struct pci_bus *parent = pdev->subordinate; |
93 | u16 cap = dpc->cap_pos, ctl; | ||
112 | 94 | ||
113 | pci_lock_rescan_remove(); | 95 | pci_lock_rescan_remove(); |
114 | list_for_each_entry_safe_reverse(dev, temp, &parent->devices, | 96 | list_for_each_entry_safe_reverse(dev, temp, &parent->devices, |
@@ -124,159 +106,127 @@ static void interrupt_event_handler(struct work_struct *work) | |||
124 | pci_unlock_rescan_remove(); | 106 | pci_unlock_rescan_remove(); |
125 | 107 | ||
126 | dpc_wait_link_inactive(dpc); | 108 | dpc_wait_link_inactive(dpc); |
127 | if (dpc->rp && dpc_wait_rp_inactive(dpc)) | 109 | if (dpc->rp_extensions && dpc_wait_rp_inactive(dpc)) |
128 | return; | 110 | return; |
129 | if (dpc->rp && dpc->rp_pio_status) { | 111 | if (dpc->rp_extensions && dpc->rp_pio_status) { |
130 | pci_write_config_dword(pdev, | 112 | pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, |
131 | dpc->cap_pos + PCI_EXP_DPC_RP_PIO_STATUS, | 113 | dpc->rp_pio_status); |
132 | dpc->rp_pio_status); | ||
133 | dpc->rp_pio_status = 0; | 114 | dpc->rp_pio_status = 0; |
134 | } | 115 | } |
135 | 116 | ||
136 | pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, | 117 | pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS, |
137 | PCI_EXP_DPC_STATUS_TRIGGER | PCI_EXP_DPC_STATUS_INTERRUPT); | 118 | PCI_EXP_DPC_STATUS_TRIGGER | PCI_EXP_DPC_STATUS_INTERRUPT); |
138 | } | ||
139 | 119 | ||
140 | static void dpc_rp_pio_print_tlp_header(struct device *dev, | 120 | pci_read_config_word(pdev, cap + PCI_EXP_DPC_CTL, &ctl); |
141 | struct rp_pio_header_log_regs *t) | 121 | pci_write_config_word(pdev, cap + PCI_EXP_DPC_CTL, |
142 | { | 122 | ctl | PCI_EXP_DPC_CTL_INT_EN); |
143 | dev_err(dev, "TLP Header: %#010x %#010x %#010x %#010x\n", | ||
144 | t->dw0, t->dw1, t->dw2, t->dw3); | ||
145 | } | 123 | } |
146 | 124 | ||
147 | static void dpc_rp_pio_print_error(struct dpc_dev *dpc, | 125 | static void dpc_process_rp_pio_error(struct dpc_dev *dpc) |
148 | struct dpc_rp_pio_regs *rp_pio) | ||
149 | { | 126 | { |
150 | struct device *dev = &dpc->dev->device; | 127 | struct device *dev = &dpc->dev->device; |
128 | struct pci_dev *pdev = dpc->dev->port; | ||
129 | u16 cap = dpc->cap_pos, dpc_status, first_error; | ||
130 | u32 status, mask, sev, syserr, exc, dw0, dw1, dw2, dw3, log, prefix; | ||
151 | int i; | 131 | int i; |
152 | u32 status; | ||
153 | 132 | ||
133 | pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, &status); | ||
134 | pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_MASK, &mask); | ||
154 | dev_err(dev, "rp_pio_status: %#010x, rp_pio_mask: %#010x\n", | 135 | dev_err(dev, "rp_pio_status: %#010x, rp_pio_mask: %#010x\n", |
155 | rp_pio->status, rp_pio->mask); | 136 | status, mask); |
137 | |||
138 | dpc->rp_pio_status = status; | ||
156 | 139 | ||
140 | pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SEVERITY, &sev); | ||
141 | pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SYSERROR, &syserr); | ||
142 | pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_EXCEPTION, &exc); | ||
157 | dev_err(dev, "RP PIO severity=%#010x, syserror=%#010x, exception=%#010x\n", | 143 | dev_err(dev, "RP PIO severity=%#010x, syserror=%#010x, exception=%#010x\n", |
158 | rp_pio->severity, rp_pio->syserror, rp_pio->exception); | 144 | sev, syserr, exc); |
159 | 145 | ||
160 | status = (rp_pio->status & ~rp_pio->mask); | 146 | /* Get First Error Pointer */ |
147 | pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &dpc_status); | ||
148 | first_error = (dpc_status & 0x1f00) >> 8; | ||
161 | 149 | ||
150 | status &= ~mask; | ||
162 | for (i = 0; i < ARRAY_SIZE(rp_pio_error_string); i++) { | 151 | for (i = 0; i < ARRAY_SIZE(rp_pio_error_string); i++) { |
163 | if (!(status & (1 << i))) | 152 | if (status & (1 << i)) |
164 | continue; | 153 | dev_err(dev, "[%2d] %s%s\n", i, rp_pio_error_string[i], |
165 | 154 | first_error == i ? " (First)" : ""); | |
166 | dev_err(dev, "[%2d] %s%s\n", i, rp_pio_error_string[i], | ||
167 | rp_pio->first_error == i ? " (First)" : ""); | ||
168 | } | 155 | } |
169 | 156 | ||
170 | dpc_rp_pio_print_tlp_header(dev, &rp_pio->header_log); | 157 | if (dpc->rp_log_size < 4) |
171 | if (rp_pio->log_size == 4) | ||
172 | return; | 158 | return; |
173 | dev_err(dev, "RP PIO ImpSpec Log %#010x\n", rp_pio->impspec_log); | 159 | pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG, |
160 | &dw0); | ||
161 | pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 4, | ||
162 | &dw1); | ||
163 | pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 8, | ||
164 | &dw2); | ||
165 | pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 12, | ||
166 | &dw3); | ||
167 | dev_err(dev, "TLP Header: %#010x %#010x %#010x %#010x\n", | ||
168 | dw0, dw1, dw2, dw3); | ||
174 | 169 | ||
175 | for (i = 0; i < rp_pio->log_size - 5; i++) | 170 | if (dpc->rp_log_size < 5) |
176 | dev_err(dev, "TLP Prefix Header: dw%d, %#010x\n", i, | 171 | return; |
177 | rp_pio->tlp_prefix_log[i]); | 172 | pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, &log); |
173 | dev_err(dev, "RP PIO ImpSpec Log %#010x\n", log); | ||
174 | |||
175 | for (i = 0; i < dpc->rp_log_size - 5; i++) { | ||
176 | pci_read_config_dword(pdev, | ||
177 | cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, &prefix); | ||
178 | dev_err(dev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix); | ||
179 | } | ||
178 | } | 180 | } |
179 | 181 | ||
180 | static void dpc_rp_pio_get_info(struct dpc_dev *dpc, | 182 | static irqreturn_t dpc_irq(int irq, void *context) |
181 | struct dpc_rp_pio_regs *rp_pio) | ||
182 | { | 183 | { |
184 | struct dpc_dev *dpc = (struct dpc_dev *)context; | ||
183 | struct pci_dev *pdev = dpc->dev->port; | 185 | struct pci_dev *pdev = dpc->dev->port; |
184 | struct device *dev = &dpc->dev->device; | 186 | struct device *dev = &dpc->dev->device; |
185 | int i; | 187 | u16 cap = dpc->cap_pos, ctl, status, source, reason, ext_reason; |
186 | u16 cap; | ||
187 | u16 status; | ||
188 | |||
189 | pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_STATUS, | ||
190 | &rp_pio->status); | ||
191 | pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_MASK, | ||
192 | &rp_pio->mask); | ||
193 | |||
194 | pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_SEVERITY, | ||
195 | &rp_pio->severity); | ||
196 | pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_SYSERROR, | ||
197 | &rp_pio->syserror); | ||
198 | pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_EXCEPTION, | ||
199 | &rp_pio->exception); | ||
200 | 188 | ||
201 | /* Get First Error Pointer */ | 189 | pci_read_config_word(pdev, cap + PCI_EXP_DPC_CTL, &ctl); |
202 | pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status); | ||
203 | rp_pio->first_error = (status & 0x1f00) >> 8; | ||
204 | 190 | ||
205 | pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap); | 191 | if (!(ctl & PCI_EXP_DPC_CTL_INT_EN) || ctl == (u16)(~0)) |
206 | rp_pio->log_size = (cap & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8; | 192 | return IRQ_NONE; |
207 | if (rp_pio->log_size < 4 || rp_pio->log_size > 9) { | ||
208 | dev_err(dev, "RP PIO log size %u is invalid\n", | ||
209 | rp_pio->log_size); | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | pci_read_config_dword(pdev, | ||
214 | dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG, | ||
215 | &rp_pio->header_log.dw0); | ||
216 | pci_read_config_dword(pdev, | ||
217 | dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 4, | ||
218 | &rp_pio->header_log.dw1); | ||
219 | pci_read_config_dword(pdev, | ||
220 | dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 8, | ||
221 | &rp_pio->header_log.dw2); | ||
222 | pci_read_config_dword(pdev, | ||
223 | dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 12, | ||
224 | &rp_pio->header_log.dw3); | ||
225 | if (rp_pio->log_size == 4) | ||
226 | return; | ||
227 | |||
228 | pci_read_config_dword(pdev, | ||
229 | dpc->cap_pos + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, | ||
230 | &rp_pio->impspec_log); | ||
231 | for (i = 0; i < rp_pio->log_size - 5; i++) | ||
232 | pci_read_config_dword(pdev, | ||
233 | dpc->cap_pos + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, | ||
234 | &rp_pio->tlp_prefix_log[i]); | ||
235 | } | ||
236 | 193 | ||
237 | static void dpc_process_rp_pio_error(struct dpc_dev *dpc) | 194 | pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status); |
238 | { | ||
239 | struct dpc_rp_pio_regs rp_pio_regs; | ||
240 | 195 | ||
241 | dpc_rp_pio_get_info(dpc, &rp_pio_regs); | 196 | if (!(status & PCI_EXP_DPC_STATUS_INTERRUPT)) |
242 | dpc_rp_pio_print_error(dpc, &rp_pio_regs); | 197 | return IRQ_NONE; |
243 | 198 | ||
244 | dpc->rp_pio_status = rp_pio_regs.status; | 199 | if (!(status & PCI_EXP_DPC_STATUS_TRIGGER)) { |
245 | } | 200 | pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS, |
201 | PCI_EXP_DPC_STATUS_INTERRUPT); | ||
202 | return IRQ_HANDLED; | ||
203 | } | ||
246 | 204 | ||
247 | static irqreturn_t dpc_irq(int irq, void *context) | 205 | pci_write_config_word(pdev, cap + PCI_EXP_DPC_CTL, |
248 | { | 206 | ctl & ~PCI_EXP_DPC_CTL_INT_EN); |
249 | struct dpc_dev *dpc = (struct dpc_dev *)context; | ||
250 | struct pci_dev *pdev = dpc->dev->port; | ||
251 | struct device *dev = &dpc->dev->device; | ||
252 | u16 status, source; | ||
253 | 207 | ||
254 | pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status); | 208 | pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID, |
255 | pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_SOURCE_ID, | ||
256 | &source); | 209 | &source); |
257 | if (!status || status == (u16)(~0)) | ||
258 | return IRQ_NONE; | ||
259 | 210 | ||
260 | dev_info(dev, "DPC containment event, status:%#06x source:%#06x\n", | 211 | dev_info(dev, "DPC containment event, status:%#06x source:%#06x\n", |
261 | status, source); | 212 | status, source); |
262 | 213 | ||
263 | if (status & PCI_EXP_DPC_STATUS_TRIGGER) { | 214 | reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN) >> 1; |
264 | u16 reason = (status >> 1) & 0x3; | 215 | ext_reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT) >> 5; |
265 | u16 ext_reason = (status >> 5) & 0x3; | 216 | |
266 | 217 | dev_warn(dev, "DPC %s detected, remove downstream devices\n", | |
267 | dev_warn(dev, "DPC %s detected, remove downstream devices\n", | 218 | (reason == 0) ? "unmasked uncorrectable error" : |
268 | (reason == 0) ? "unmasked uncorrectable error" : | 219 | (reason == 1) ? "ERR_NONFATAL" : |
269 | (reason == 1) ? "ERR_NONFATAL" : | 220 | (reason == 2) ? "ERR_FATAL" : |
270 | (reason == 2) ? "ERR_FATAL" : | 221 | (ext_reason == 0) ? "RP PIO error" : |
271 | (ext_reason == 0) ? "RP PIO error" : | 222 | (ext_reason == 1) ? "software trigger" : |
272 | (ext_reason == 1) ? "software trigger" : | 223 | "reserved error"); |
273 | "reserved error"); | 224 | /* show RP PIO error detail information */ |
274 | /* show RP PIO error detail information */ | 225 | if (dpc->rp_extensions && reason == 3 && ext_reason == 0) |
275 | if (reason == 3 && ext_reason == 0) | 226 | dpc_process_rp_pio_error(dpc); |
276 | dpc_process_rp_pio_error(dpc); | 227 | |
277 | 228 | schedule_work(&dpc->work); | |
278 | schedule_work(&dpc->work); | 229 | |
279 | } | ||
280 | return IRQ_HANDLED; | 230 | return IRQ_HANDLED; |
281 | } | 231 | } |
282 | 232 | ||
@@ -289,13 +239,16 @@ static int dpc_probe(struct pcie_device *dev) | |||
289 | int status; | 239 | int status; |
290 | u16 ctl, cap; | 240 | u16 ctl, cap; |
291 | 241 | ||
242 | if (pcie_aer_get_firmware_first(pdev)) | ||
243 | return -ENOTSUPP; | ||
244 | |||
292 | dpc = devm_kzalloc(device, sizeof(*dpc), GFP_KERNEL); | 245 | dpc = devm_kzalloc(device, sizeof(*dpc), GFP_KERNEL); |
293 | if (!dpc) | 246 | if (!dpc) |
294 | return -ENOMEM; | 247 | return -ENOMEM; |
295 | 248 | ||
296 | dpc->cap_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DPC); | 249 | dpc->cap_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DPC); |
297 | dpc->dev = dev; | 250 | dpc->dev = dev; |
298 | INIT_WORK(&dpc->work, interrupt_event_handler); | 251 | INIT_WORK(&dpc->work, dpc_work); |
299 | set_service_data(dev, dpc); | 252 | set_service_data(dev, dpc); |
300 | 253 | ||
301 | status = devm_request_irq(device, dev->irq, dpc_irq, IRQF_SHARED, | 254 | status = devm_request_irq(device, dev->irq, dpc_irq, IRQF_SHARED, |
@@ -309,15 +262,23 @@ static int dpc_probe(struct pcie_device *dev) | |||
309 | pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap); | 262 | pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap); |
310 | pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl); | 263 | pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl); |
311 | 264 | ||
312 | dpc->rp = (cap & PCI_EXP_DPC_CAP_RP_EXT); | 265 | dpc->rp_extensions = (cap & PCI_EXP_DPC_CAP_RP_EXT); |
266 | if (dpc->rp_extensions) { | ||
267 | dpc->rp_log_size = (cap & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8; | ||
268 | if (dpc->rp_log_size < 4 || dpc->rp_log_size > 9) { | ||
269 | dev_err(device, "RP PIO log size %u is invalid\n", | ||
270 | dpc->rp_log_size); | ||
271 | dpc->rp_log_size = 0; | ||
272 | } | ||
273 | } | ||
313 | 274 | ||
314 | ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN; | 275 | ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN; |
315 | pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl); | 276 | pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl); |
316 | 277 | ||
317 | dev_info(device, "DPC error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n", | 278 | dev_info(device, "DPC error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n", |
318 | cap & 0xf, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT), | 279 | cap & PCI_EXP_DPC_IRQ, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT), |
319 | FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP), | 280 | FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP), |
320 | FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), (cap >> 8) & 0xf, | 281 | FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), dpc->rp_log_size, |
321 | FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE)); | 282 | FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE)); |
322 | return status; | 283 | return status; |
323 | } | 284 | } |
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index a59210350c44..ef3bad4ad010 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -216,9 +216,9 @@ static int get_port_device_capability(struct pci_dev *dev) | |||
216 | return 0; | 216 | return 0; |
217 | 217 | ||
218 | cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP | 218 | cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP |
219 | | PCIE_PORT_SERVICE_VC | PCIE_PORT_SERVICE_DPC; | 219 | | PCIE_PORT_SERVICE_VC; |
220 | if (pci_aer_available()) | 220 | if (pci_aer_available()) |
221 | cap_mask |= PCIE_PORT_SERVICE_AER; | 221 | cap_mask |= PCIE_PORT_SERVICE_AER | PCIE_PORT_SERVICE_DPC; |
222 | 222 | ||
223 | if (pcie_ports_auto) | 223 | if (pcie_ports_auto) |
224 | pcie_port_platform_notify(dev, &cap_mask); | 224 | pcie_port_platform_notify(dev, &cap_mask); |
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index 70c2b2ade048..66d71461d2f0 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h | |||
@@ -966,26 +966,28 @@ | |||
966 | 966 | ||
967 | /* Downstream Port Containment */ | 967 | /* Downstream Port Containment */ |
968 | #define PCI_EXP_DPC_CAP 4 /* DPC Capability */ | 968 | #define PCI_EXP_DPC_CAP 4 /* DPC Capability */ |
969 | #define PCI_EXP_DPC_IRQ 0x1f /* DPC Interrupt Message Number */ | 969 | #define PCI_EXP_DPC_IRQ 0x001F /* Interrupt Message Number */ |
970 | #define PCI_EXP_DPC_CAP_RP_EXT 0x20 /* Root Port Extensions for DPC */ | 970 | #define PCI_EXP_DPC_CAP_RP_EXT 0x0020 /* Root Port Extensions */ |
971 | #define PCI_EXP_DPC_CAP_POISONED_TLP 0x40 /* Poisoned TLP Egress Blocking Supported */ | 971 | #define PCI_EXP_DPC_CAP_POISONED_TLP 0x0040 /* Poisoned TLP Egress Blocking Supported */ |
972 | #define PCI_EXP_DPC_CAP_SW_TRIGGER 0x80 /* Software Triggering Supported */ | 972 | #define PCI_EXP_DPC_CAP_SW_TRIGGER 0x0080 /* Software Triggering Supported */ |
973 | #define PCI_EXP_DPC_RP_PIO_LOG_SIZE 0xF00 /* RP PIO log size */ | 973 | #define PCI_EXP_DPC_RP_PIO_LOG_SIZE 0x0F00 /* RP PIO Log Size */ |
974 | #define PCI_EXP_DPC_CAP_DL_ACTIVE 0x1000 /* ERR_COR signal on DL_Active supported */ | 974 | #define PCI_EXP_DPC_CAP_DL_ACTIVE 0x1000 /* ERR_COR signal on DL_Active supported */ |
975 | 975 | ||
976 | #define PCI_EXP_DPC_CTL 6 /* DPC control */ | 976 | #define PCI_EXP_DPC_CTL 6 /* DPC control */ |
977 | #define PCI_EXP_DPC_CTL_EN_NONFATAL 0x02 /* Enable trigger on ERR_NONFATAL message */ | 977 | #define PCI_EXP_DPC_CTL_EN_NONFATAL 0x0002 /* Enable trigger on ERR_NONFATAL message */ |
978 | #define PCI_EXP_DPC_CTL_INT_EN 0x08 /* DPC Interrupt Enable */ | 978 | #define PCI_EXP_DPC_CTL_INT_EN 0x0008 /* DPC Interrupt Enable */ |
979 | 979 | ||
980 | #define PCI_EXP_DPC_STATUS 8 /* DPC Status */ | 980 | #define PCI_EXP_DPC_STATUS 8 /* DPC Status */ |
981 | #define PCI_EXP_DPC_STATUS_TRIGGER 0x01 /* Trigger Status */ | 981 | #define PCI_EXP_DPC_STATUS_TRIGGER 0x0001 /* Trigger Status */ |
982 | #define PCI_EXP_DPC_STATUS_INTERRUPT 0x08 /* Interrupt Status */ | 982 | #define PCI_EXP_DPC_STATUS_TRIGGER_RSN 0x0006 /* Trigger Reason */ |
983 | #define PCI_EXP_DPC_RP_BUSY 0x10 /* Root Port Busy */ | 983 | #define PCI_EXP_DPC_STATUS_INTERRUPT 0x0008 /* Interrupt Status */ |
984 | #define PCI_EXP_DPC_RP_BUSY 0x0010 /* Root Port Busy */ | ||
985 | #define PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT 0x0060 /* Trig Reason Extension */ | ||
984 | 986 | ||
985 | #define PCI_EXP_DPC_SOURCE_ID 10 /* DPC Source Identifier */ | 987 | #define PCI_EXP_DPC_SOURCE_ID 10 /* DPC Source Identifier */ |
986 | 988 | ||
987 | #define PCI_EXP_DPC_RP_PIO_STATUS 0x0C /* RP PIO Status */ | 989 | #define PCI_EXP_DPC_RP_PIO_STATUS 0x0C /* RP PIO Status */ |
988 | #define PCI_EXP_DPC_RP_PIO_MASK 0x10 /* RP PIO MASK */ | 990 | #define PCI_EXP_DPC_RP_PIO_MASK 0x10 /* RP PIO Mask */ |
989 | #define PCI_EXP_DPC_RP_PIO_SEVERITY 0x14 /* RP PIO Severity */ | 991 | #define PCI_EXP_DPC_RP_PIO_SEVERITY 0x14 /* RP PIO Severity */ |
990 | #define PCI_EXP_DPC_RP_PIO_SYSERROR 0x18 /* RP PIO SysError */ | 992 | #define PCI_EXP_DPC_RP_PIO_SYSERROR 0x18 /* RP PIO SysError */ |
991 | #define PCI_EXP_DPC_RP_PIO_EXCEPTION 0x1C /* RP PIO Exception */ | 993 | #define PCI_EXP_DPC_RP_PIO_EXCEPTION 0x1C /* RP PIO Exception */ |