.. | .. |
---|
12 | 12 | * Andrew Patterson <andrew.patterson@hp.com> |
---|
13 | 13 | */ |
---|
14 | 14 | |
---|
| 15 | +#define pr_fmt(fmt) "AER: " fmt |
---|
| 16 | +#define dev_fmt pr_fmt |
---|
| 17 | + |
---|
| 18 | +#include <linux/bitops.h> |
---|
15 | 19 | #include <linux/cper.h> |
---|
16 | 20 | #include <linux/pci.h> |
---|
17 | 21 | #include <linux/pci-acpi.h> |
---|
.. | .. |
---|
30 | 34 | #include "../pci.h" |
---|
31 | 35 | #include "portdrv.h" |
---|
32 | 36 | |
---|
33 | | -#define AER_ERROR_SOURCES_MAX 100 |
---|
| 37 | +#define AER_ERROR_SOURCES_MAX 128 |
---|
34 | 38 | |
---|
35 | 39 | #define AER_MAX_TYPEOF_COR_ERRS 16 /* as per PCI_ERR_COR_STATUS */ |
---|
36 | | -#define AER_MAX_TYPEOF_UNCOR_ERRS 26 /* as per PCI_ERR_UNCOR_STATUS*/ |
---|
| 40 | +#define AER_MAX_TYPEOF_UNCOR_ERRS 27 /* as per PCI_ERR_UNCOR_STATUS*/ |
---|
37 | 41 | |
---|
38 | 42 | struct aer_err_source { |
---|
39 | 43 | unsigned int status; |
---|
.. | .. |
---|
42 | 46 | |
---|
43 | 47 | struct aer_rpc { |
---|
44 | 48 | struct pci_dev *rpd; /* Root Port device */ |
---|
45 | | - struct work_struct dpc_handler; |
---|
46 | | - struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX]; |
---|
47 | | - struct aer_err_info e_info; |
---|
48 | | - unsigned short prod_idx; /* Error Producer Index */ |
---|
49 | | - unsigned short cons_idx; /* Error Consumer Index */ |
---|
50 | | - int isr; |
---|
51 | | - spinlock_t e_lock; /* |
---|
52 | | - * Lock access to Error Status/ID Regs |
---|
53 | | - * and error producer/consumer index |
---|
54 | | - */ |
---|
55 | | - struct mutex rpc_mutex; /* |
---|
56 | | - * only one thread could do |
---|
57 | | - * recovery on the same |
---|
58 | | - * root port hierarchy |
---|
59 | | - */ |
---|
| 49 | + DECLARE_KFIFO(aer_fifo, struct aer_err_source, AER_ERROR_SOURCES_MAX); |
---|
60 | 50 | }; |
---|
61 | 51 | |
---|
62 | 52 | /* AER stats for the device */ |
---|
.. | .. |
---|
111 | 101 | #define ERR_COR_ID(d) (d & 0xffff) |
---|
112 | 102 | #define ERR_UNCOR_ID(d) (d >> 16) |
---|
113 | 103 | |
---|
| 104 | +#define AER_ERR_STATUS_MASK (PCI_ERR_ROOT_UNCOR_RCV | \ |
---|
| 105 | + PCI_ERR_ROOT_COR_RCV | \ |
---|
| 106 | + PCI_ERR_ROOT_MULTI_COR_RCV | \ |
---|
| 107 | + PCI_ERR_ROOT_MULTI_UNCOR_RCV) |
---|
| 108 | + |
---|
114 | 109 | static int pcie_aer_disable; |
---|
| 110 | +static pci_ers_result_t aer_root_reset(struct pci_dev *dev); |
---|
115 | 111 | |
---|
116 | 112 | void pci_no_aer(void) |
---|
117 | 113 | { |
---|
.. | .. |
---|
131 | 127 | |
---|
132 | 128 | static int ecrc_policy = ECRC_POLICY_DEFAULT; |
---|
133 | 129 | |
---|
134 | | -static const char *ecrc_policy_str[] = { |
---|
| 130 | +static const char * const ecrc_policy_str[] = { |
---|
135 | 131 | [ECRC_POLICY_DEFAULT] = "bios", |
---|
136 | 132 | [ECRC_POLICY_OFF] = "off", |
---|
137 | 133 | [ECRC_POLICY_ON] = "on" |
---|
.. | .. |
---|
145 | 141 | */ |
---|
146 | 142 | static int enable_ecrc_checking(struct pci_dev *dev) |
---|
147 | 143 | { |
---|
148 | | - int pos; |
---|
| 144 | + int aer = dev->aer_cap; |
---|
149 | 145 | u32 reg32; |
---|
150 | 146 | |
---|
151 | | - if (!pci_is_pcie(dev)) |
---|
| 147 | + if (!aer) |
---|
152 | 148 | return -ENODEV; |
---|
153 | 149 | |
---|
154 | | - pos = dev->aer_cap; |
---|
155 | | - if (!pos) |
---|
156 | | - return -ENODEV; |
---|
157 | | - |
---|
158 | | - pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); |
---|
| 150 | + pci_read_config_dword(dev, aer + PCI_ERR_CAP, ®32); |
---|
159 | 151 | if (reg32 & PCI_ERR_CAP_ECRC_GENC) |
---|
160 | 152 | reg32 |= PCI_ERR_CAP_ECRC_GENE; |
---|
161 | 153 | if (reg32 & PCI_ERR_CAP_ECRC_CHKC) |
---|
162 | 154 | reg32 |= PCI_ERR_CAP_ECRC_CHKE; |
---|
163 | | - pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); |
---|
| 155 | + pci_write_config_dword(dev, aer + PCI_ERR_CAP, reg32); |
---|
164 | 156 | |
---|
165 | 157 | return 0; |
---|
166 | 158 | } |
---|
.. | .. |
---|
173 | 165 | */ |
---|
174 | 166 | static int disable_ecrc_checking(struct pci_dev *dev) |
---|
175 | 167 | { |
---|
176 | | - int pos; |
---|
| 168 | + int aer = dev->aer_cap; |
---|
177 | 169 | u32 reg32; |
---|
178 | 170 | |
---|
179 | | - if (!pci_is_pcie(dev)) |
---|
| 171 | + if (!aer) |
---|
180 | 172 | return -ENODEV; |
---|
181 | 173 | |
---|
182 | | - pos = dev->aer_cap; |
---|
183 | | - if (!pos) |
---|
184 | | - return -ENODEV; |
---|
185 | | - |
---|
186 | | - pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); |
---|
| 174 | + pci_read_config_dword(dev, aer + PCI_ERR_CAP, ®32); |
---|
187 | 175 | reg32 &= ~(PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); |
---|
188 | | - pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); |
---|
| 176 | + pci_write_config_dword(dev, aer + PCI_ERR_CAP, reg32); |
---|
189 | 177 | |
---|
190 | 178 | return 0; |
---|
191 | 179 | } |
---|
.. | .. |
---|
212 | 200 | |
---|
213 | 201 | /** |
---|
214 | 202 | * pcie_ecrc_get_policy - parse kernel command-line ecrc option |
---|
| 203 | + * @str: ECRC policy from kernel command line to use |
---|
215 | 204 | */ |
---|
216 | 205 | void pcie_ecrc_get_policy(char *str) |
---|
217 | 206 | { |
---|
218 | 207 | int i; |
---|
219 | 208 | |
---|
220 | | - for (i = 0; i < ARRAY_SIZE(ecrc_policy_str); i++) |
---|
221 | | - if (!strncmp(str, ecrc_policy_str[i], |
---|
222 | | - strlen(ecrc_policy_str[i]))) |
---|
223 | | - break; |
---|
224 | | - if (i >= ARRAY_SIZE(ecrc_policy_str)) |
---|
| 209 | + i = match_string(ecrc_policy_str, ARRAY_SIZE(ecrc_policy_str), str); |
---|
| 210 | + if (i < 0) |
---|
225 | 211 | return; |
---|
226 | 212 | |
---|
227 | 213 | ecrc_policy = i; |
---|
228 | 214 | } |
---|
229 | 215 | #endif /* CONFIG_PCIE_ECRC */ |
---|
230 | 216 | |
---|
231 | | -#ifdef CONFIG_ACPI_APEI |
---|
232 | | -static inline int hest_match_pci(struct acpi_hest_aer_common *p, |
---|
233 | | - struct pci_dev *pci) |
---|
234 | | -{ |
---|
235 | | - return ACPI_HEST_SEGMENT(p->bus) == pci_domain_nr(pci->bus) && |
---|
236 | | - ACPI_HEST_BUS(p->bus) == pci->bus->number && |
---|
237 | | - p->device == PCI_SLOT(pci->devfn) && |
---|
238 | | - p->function == PCI_FUNC(pci->devfn); |
---|
239 | | -} |
---|
240 | | - |
---|
241 | | -static inline bool hest_match_type(struct acpi_hest_header *hest_hdr, |
---|
242 | | - struct pci_dev *dev) |
---|
243 | | -{ |
---|
244 | | - u16 hest_type = hest_hdr->type; |
---|
245 | | - u8 pcie_type = pci_pcie_type(dev); |
---|
246 | | - |
---|
247 | | - if ((hest_type == ACPI_HEST_TYPE_AER_ROOT_PORT && |
---|
248 | | - pcie_type == PCI_EXP_TYPE_ROOT_PORT) || |
---|
249 | | - (hest_type == ACPI_HEST_TYPE_AER_ENDPOINT && |
---|
250 | | - pcie_type == PCI_EXP_TYPE_ENDPOINT) || |
---|
251 | | - (hest_type == ACPI_HEST_TYPE_AER_BRIDGE && |
---|
252 | | - (dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)) |
---|
253 | | - return true; |
---|
254 | | - return false; |
---|
255 | | -} |
---|
256 | | - |
---|
257 | | -struct aer_hest_parse_info { |
---|
258 | | - struct pci_dev *pci_dev; |
---|
259 | | - int firmware_first; |
---|
260 | | -}; |
---|
261 | | - |
---|
262 | | -static int hest_source_is_pcie_aer(struct acpi_hest_header *hest_hdr) |
---|
263 | | -{ |
---|
264 | | - if (hest_hdr->type == ACPI_HEST_TYPE_AER_ROOT_PORT || |
---|
265 | | - hest_hdr->type == ACPI_HEST_TYPE_AER_ENDPOINT || |
---|
266 | | - hest_hdr->type == ACPI_HEST_TYPE_AER_BRIDGE) |
---|
267 | | - return 1; |
---|
268 | | - return 0; |
---|
269 | | -} |
---|
270 | | - |
---|
271 | | -static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data) |
---|
272 | | -{ |
---|
273 | | - struct aer_hest_parse_info *info = data; |
---|
274 | | - struct acpi_hest_aer_common *p; |
---|
275 | | - int ff; |
---|
276 | | - |
---|
277 | | - if (!hest_source_is_pcie_aer(hest_hdr)) |
---|
278 | | - return 0; |
---|
279 | | - |
---|
280 | | - p = (struct acpi_hest_aer_common *)(hest_hdr + 1); |
---|
281 | | - ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); |
---|
282 | | - |
---|
283 | | - /* |
---|
284 | | - * If no specific device is supplied, determine whether |
---|
285 | | - * FIRMWARE_FIRST is set for *any* PCIe device. |
---|
286 | | - */ |
---|
287 | | - if (!info->pci_dev) { |
---|
288 | | - info->firmware_first |= ff; |
---|
289 | | - return 0; |
---|
290 | | - } |
---|
291 | | - |
---|
292 | | - /* Otherwise, check the specific device */ |
---|
293 | | - if (p->flags & ACPI_HEST_GLOBAL) { |
---|
294 | | - if (hest_match_type(hest_hdr, info->pci_dev)) |
---|
295 | | - info->firmware_first = ff; |
---|
296 | | - } else |
---|
297 | | - if (hest_match_pci(p, info->pci_dev)) |
---|
298 | | - info->firmware_first = ff; |
---|
299 | | - |
---|
300 | | - return 0; |
---|
301 | | -} |
---|
302 | | - |
---|
303 | | -static void aer_set_firmware_first(struct pci_dev *pci_dev) |
---|
304 | | -{ |
---|
305 | | - int rc; |
---|
306 | | - struct aer_hest_parse_info info = { |
---|
307 | | - .pci_dev = pci_dev, |
---|
308 | | - .firmware_first = 0, |
---|
309 | | - }; |
---|
310 | | - |
---|
311 | | - rc = apei_hest_parse(aer_hest_parse, &info); |
---|
312 | | - |
---|
313 | | - if (rc) |
---|
314 | | - pci_dev->__aer_firmware_first = 0; |
---|
315 | | - else |
---|
316 | | - pci_dev->__aer_firmware_first = info.firmware_first; |
---|
317 | | - pci_dev->__aer_firmware_first_valid = 1; |
---|
318 | | -} |
---|
319 | | - |
---|
320 | | -int pcie_aer_get_firmware_first(struct pci_dev *dev) |
---|
321 | | -{ |
---|
322 | | - if (!pci_is_pcie(dev)) |
---|
323 | | - return 0; |
---|
324 | | - |
---|
325 | | - if (pcie_ports_native) |
---|
326 | | - return 0; |
---|
327 | | - |
---|
328 | | - if (!dev->__aer_firmware_first_valid) |
---|
329 | | - aer_set_firmware_first(dev); |
---|
330 | | - return dev->__aer_firmware_first; |
---|
331 | | -} |
---|
332 | | - |
---|
333 | | -static bool aer_firmware_first; |
---|
334 | | - |
---|
335 | | -/** |
---|
336 | | - * aer_acpi_firmware_first - Check if APEI should control AER. |
---|
337 | | - */ |
---|
338 | | -bool aer_acpi_firmware_first(void) |
---|
339 | | -{ |
---|
340 | | - static bool parsed = false; |
---|
341 | | - struct aer_hest_parse_info info = { |
---|
342 | | - .pci_dev = NULL, /* Check all PCIe devices */ |
---|
343 | | - .firmware_first = 0, |
---|
344 | | - }; |
---|
345 | | - |
---|
346 | | - if (pcie_ports_native) |
---|
347 | | - return false; |
---|
348 | | - |
---|
349 | | - if (!parsed) { |
---|
350 | | - apei_hest_parse(aer_hest_parse, &info); |
---|
351 | | - aer_firmware_first = info.firmware_first; |
---|
352 | | - parsed = true; |
---|
353 | | - } |
---|
354 | | - return aer_firmware_first; |
---|
355 | | -} |
---|
356 | | -#endif |
---|
357 | | - |
---|
358 | 217 | #define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ |
---|
359 | 218 | PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) |
---|
360 | 219 | |
---|
361 | | -int pci_enable_pcie_error_reporting(struct pci_dev *dev) |
---|
| 220 | +int pcie_aer_is_native(struct pci_dev *dev) |
---|
362 | 221 | { |
---|
363 | | - if (pcie_aer_get_firmware_first(dev)) |
---|
364 | | - return -EIO; |
---|
| 222 | + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus); |
---|
365 | 223 | |
---|
366 | 224 | if (!dev->aer_cap) |
---|
| 225 | + return 0; |
---|
| 226 | + |
---|
| 227 | + return pcie_ports_native || host->native_aer; |
---|
| 228 | +} |
---|
| 229 | + |
---|
| 230 | +int pci_enable_pcie_error_reporting(struct pci_dev *dev) |
---|
| 231 | +{ |
---|
| 232 | + int rc; |
---|
| 233 | + |
---|
| 234 | + if (!pcie_aer_is_native(dev)) |
---|
367 | 235 | return -EIO; |
---|
368 | 236 | |
---|
369 | | - return pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS); |
---|
| 237 | + rc = pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS); |
---|
| 238 | + return pcibios_err_to_errno(rc); |
---|
370 | 239 | } |
---|
371 | 240 | EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting); |
---|
372 | 241 | |
---|
373 | 242 | int pci_disable_pcie_error_reporting(struct pci_dev *dev) |
---|
374 | 243 | { |
---|
375 | | - if (pcie_aer_get_firmware_first(dev)) |
---|
| 244 | + int rc; |
---|
| 245 | + |
---|
| 246 | + if (!pcie_aer_is_native(dev)) |
---|
376 | 247 | return -EIO; |
---|
377 | 248 | |
---|
378 | | - return pcie_capability_clear_word(dev, PCI_EXP_DEVCTL, |
---|
379 | | - PCI_EXP_AER_FLAGS); |
---|
| 249 | + rc = pcie_capability_clear_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS); |
---|
| 250 | + return pcibios_err_to_errno(rc); |
---|
380 | 251 | } |
---|
381 | 252 | EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting); |
---|
382 | 253 | |
---|
383 | | -void pci_aer_clear_device_status(struct pci_dev *dev) |
---|
| 254 | +int pci_aer_clear_nonfatal_status(struct pci_dev *dev) |
---|
384 | 255 | { |
---|
385 | | - u16 sta; |
---|
386 | | - |
---|
387 | | - pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta); |
---|
388 | | - pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta); |
---|
389 | | -} |
---|
390 | | - |
---|
391 | | -int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) |
---|
392 | | -{ |
---|
393 | | - int pos; |
---|
| 256 | + int aer = dev->aer_cap; |
---|
394 | 257 | u32 status, sev; |
---|
395 | 258 | |
---|
396 | | - pos = dev->aer_cap; |
---|
397 | | - if (!pos) |
---|
398 | | - return -EIO; |
---|
399 | | - |
---|
400 | | - if (pcie_aer_get_firmware_first(dev)) |
---|
| 259 | + if (!pcie_aer_is_native(dev)) |
---|
401 | 260 | return -EIO; |
---|
402 | 261 | |
---|
403 | 262 | /* Clear status bits for ERR_NONFATAL errors only */ |
---|
404 | | - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); |
---|
405 | | - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &sev); |
---|
| 263 | + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, &status); |
---|
| 264 | + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_SEVER, &sev); |
---|
406 | 265 | status &= ~sev; |
---|
407 | 266 | if (status) |
---|
408 | | - pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); |
---|
| 267 | + pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status); |
---|
409 | 268 | |
---|
410 | 269 | return 0; |
---|
411 | 270 | } |
---|
412 | | -EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status); |
---|
| 271 | +EXPORT_SYMBOL_GPL(pci_aer_clear_nonfatal_status); |
---|
413 | 272 | |
---|
414 | 273 | void pci_aer_clear_fatal_status(struct pci_dev *dev) |
---|
415 | 274 | { |
---|
416 | | - int pos; |
---|
| 275 | + int aer = dev->aer_cap; |
---|
417 | 276 | u32 status, sev; |
---|
418 | 277 | |
---|
419 | | - pos = dev->aer_cap; |
---|
420 | | - if (!pos) |
---|
421 | | - return; |
---|
422 | | - |
---|
423 | | - if (pcie_aer_get_firmware_first(dev)) |
---|
| 278 | + if (!pcie_aer_is_native(dev)) |
---|
424 | 279 | return; |
---|
425 | 280 | |
---|
426 | 281 | /* Clear status bits for ERR_FATAL errors only */ |
---|
427 | | - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); |
---|
428 | | - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &sev); |
---|
| 282 | + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, &status); |
---|
| 283 | + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_SEVER, &sev); |
---|
429 | 284 | status &= sev; |
---|
430 | 285 | if (status) |
---|
431 | | - pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); |
---|
| 286 | + pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status); |
---|
432 | 287 | } |
---|
433 | 288 | |
---|
434 | | -int pci_cleanup_aer_error_status_regs(struct pci_dev *dev) |
---|
| 289 | +/** |
---|
| 290 | + * pci_aer_raw_clear_status - Clear AER error registers. |
---|
| 291 | + * @dev: the PCI device |
---|
| 292 | + * |
---|
| 293 | + * Clearing AER error status registers unconditionally, regardless of |
---|
| 294 | + * whether they're owned by firmware or the OS. |
---|
| 295 | + * |
---|
| 296 | + * Returns 0 on success, or negative on failure. |
---|
| 297 | + */ |
---|
| 298 | +int pci_aer_raw_clear_status(struct pci_dev *dev) |
---|
435 | 299 | { |
---|
436 | | - int pos; |
---|
| 300 | + int aer = dev->aer_cap; |
---|
437 | 301 | u32 status; |
---|
438 | 302 | int port_type; |
---|
439 | 303 | |
---|
440 | | - if (!pci_is_pcie(dev)) |
---|
441 | | - return -ENODEV; |
---|
442 | | - |
---|
443 | | - pos = dev->aer_cap; |
---|
444 | | - if (!pos) |
---|
445 | | - return -EIO; |
---|
446 | | - |
---|
447 | | - if (pcie_aer_get_firmware_first(dev)) |
---|
| 304 | + if (!aer) |
---|
448 | 305 | return -EIO; |
---|
449 | 306 | |
---|
450 | 307 | port_type = pci_pcie_type(dev); |
---|
451 | | - if (port_type == PCI_EXP_TYPE_ROOT_PORT) { |
---|
452 | | - pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status); |
---|
453 | | - pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status); |
---|
| 308 | + if (port_type == PCI_EXP_TYPE_ROOT_PORT || |
---|
| 309 | + port_type == PCI_EXP_TYPE_RC_EC) { |
---|
| 310 | + pci_read_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, &status); |
---|
| 311 | + pci_write_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, status); |
---|
454 | 312 | } |
---|
455 | 313 | |
---|
456 | | - pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); |
---|
457 | | - pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, status); |
---|
| 314 | + pci_read_config_dword(dev, aer + PCI_ERR_COR_STATUS, &status); |
---|
| 315 | + pci_write_config_dword(dev, aer + PCI_ERR_COR_STATUS, status); |
---|
458 | 316 | |
---|
459 | | - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); |
---|
460 | | - pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); |
---|
| 317 | + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, &status); |
---|
| 318 | + pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status); |
---|
461 | 319 | |
---|
462 | 320 | return 0; |
---|
| 321 | +} |
---|
| 322 | + |
---|
| 323 | +int pci_aer_clear_status(struct pci_dev *dev) |
---|
| 324 | +{ |
---|
| 325 | + if (!pcie_aer_is_native(dev)) |
---|
| 326 | + return -EIO; |
---|
| 327 | + |
---|
| 328 | + return pci_aer_raw_clear_status(dev); |
---|
| 329 | +} |
---|
| 330 | + |
---|
| 331 | +void pci_save_aer_state(struct pci_dev *dev) |
---|
| 332 | +{ |
---|
| 333 | + int aer = dev->aer_cap; |
---|
| 334 | + struct pci_cap_saved_state *save_state; |
---|
| 335 | + u32 *cap; |
---|
| 336 | + |
---|
| 337 | + if (!aer) |
---|
| 338 | + return; |
---|
| 339 | + |
---|
| 340 | + save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_ERR); |
---|
| 341 | + if (!save_state) |
---|
| 342 | + return; |
---|
| 343 | + |
---|
| 344 | + cap = &save_state->cap.data[0]; |
---|
| 345 | + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, cap++); |
---|
| 346 | + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_SEVER, cap++); |
---|
| 347 | + pci_read_config_dword(dev, aer + PCI_ERR_COR_MASK, cap++); |
---|
| 348 | + pci_read_config_dword(dev, aer + PCI_ERR_CAP, cap++); |
---|
| 349 | + if (pcie_cap_has_rtctl(dev)) |
---|
| 350 | + pci_read_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, cap++); |
---|
| 351 | +} |
---|
| 352 | + |
---|
| 353 | +void pci_restore_aer_state(struct pci_dev *dev) |
---|
| 354 | +{ |
---|
| 355 | + int aer = dev->aer_cap; |
---|
| 356 | + struct pci_cap_saved_state *save_state; |
---|
| 357 | + u32 *cap; |
---|
| 358 | + |
---|
| 359 | + if (!aer) |
---|
| 360 | + return; |
---|
| 361 | + |
---|
| 362 | + save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_ERR); |
---|
| 363 | + if (!save_state) |
---|
| 364 | + return; |
---|
| 365 | + |
---|
| 366 | + cap = &save_state->cap.data[0]; |
---|
| 367 | + pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, *cap++); |
---|
| 368 | + pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_SEVER, *cap++); |
---|
| 369 | + pci_write_config_dword(dev, aer + PCI_ERR_COR_MASK, *cap++); |
---|
| 370 | + pci_write_config_dword(dev, aer + PCI_ERR_CAP, *cap++); |
---|
| 371 | + if (pcie_cap_has_rtctl(dev)) |
---|
| 372 | + pci_write_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, *cap++); |
---|
463 | 373 | } |
---|
464 | 374 | |
---|
465 | 375 | void pci_aer_init(struct pci_dev *dev) |
---|
466 | 376 | { |
---|
| 377 | + int n; |
---|
| 378 | + |
---|
467 | 379 | dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); |
---|
| 380 | + if (!dev->aer_cap) |
---|
| 381 | + return; |
---|
468 | 382 | |
---|
469 | | - if (dev->aer_cap) |
---|
470 | | - dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL); |
---|
| 383 | + dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL); |
---|
471 | 384 | |
---|
472 | | - pci_cleanup_aer_error_status_regs(dev); |
---|
| 385 | + /* |
---|
| 386 | + * We save/restore PCI_ERR_UNCOR_MASK, PCI_ERR_UNCOR_SEVER, |
---|
| 387 | + * PCI_ERR_COR_MASK, and PCI_ERR_CAP. Root and Root Complex Event |
---|
| 388 | + * Collectors also implement PCI_ERR_ROOT_COMMAND (PCIe r5.0, sec |
---|
| 389 | + * 7.8.4). |
---|
| 390 | + */ |
---|
| 391 | + n = pcie_cap_has_rtctl(dev) ? 5 : 4; |
---|
| 392 | + pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_ERR, sizeof(u32) * n); |
---|
| 393 | + |
---|
| 394 | + pci_aer_clear_status(dev); |
---|
473 | 395 | } |
---|
474 | 396 | |
---|
475 | 397 | void pci_aer_exit(struct pci_dev *dev) |
---|
.. | .. |
---|
528 | 450 | "Transaction Layer" |
---|
529 | 451 | }; |
---|
530 | 452 | |
---|
531 | | -static const char *aer_correctable_error_string[AER_MAX_TYPEOF_COR_ERRS] = { |
---|
| 453 | +static const char *aer_correctable_error_string[] = { |
---|
532 | 454 | "RxErr", /* Bit Position 0 */ |
---|
533 | 455 | NULL, |
---|
534 | 456 | NULL, |
---|
.. | .. |
---|
545 | 467 | "NonFatalErr", /* Bit Position 13 */ |
---|
546 | 468 | "CorrIntErr", /* Bit Position 14 */ |
---|
547 | 469 | "HeaderOF", /* Bit Position 15 */ |
---|
| 470 | + NULL, /* Bit Position 16 */ |
---|
| 471 | + NULL, /* Bit Position 17 */ |
---|
| 472 | + NULL, /* Bit Position 18 */ |
---|
| 473 | + NULL, /* Bit Position 19 */ |
---|
| 474 | + NULL, /* Bit Position 20 */ |
---|
| 475 | + NULL, /* Bit Position 21 */ |
---|
| 476 | + NULL, /* Bit Position 22 */ |
---|
| 477 | + NULL, /* Bit Position 23 */ |
---|
| 478 | + NULL, /* Bit Position 24 */ |
---|
| 479 | + NULL, /* Bit Position 25 */ |
---|
| 480 | + NULL, /* Bit Position 26 */ |
---|
| 481 | + NULL, /* Bit Position 27 */ |
---|
| 482 | + NULL, /* Bit Position 28 */ |
---|
| 483 | + NULL, /* Bit Position 29 */ |
---|
| 484 | + NULL, /* Bit Position 30 */ |
---|
| 485 | + NULL, /* Bit Position 31 */ |
---|
548 | 486 | }; |
---|
549 | 487 | |
---|
550 | | -static const char *aer_uncorrectable_error_string[AER_MAX_TYPEOF_UNCOR_ERRS] = { |
---|
| 488 | +static const char *aer_uncorrectable_error_string[] = { |
---|
551 | 489 | "Undefined", /* Bit Position 0 */ |
---|
552 | 490 | NULL, |
---|
553 | 491 | NULL, |
---|
.. | .. |
---|
574 | 512 | "BlockedTLP", /* Bit Position 23 */ |
---|
575 | 513 | "AtomicOpBlocked", /* Bit Position 24 */ |
---|
576 | 514 | "TLPBlockedErr", /* Bit Position 25 */ |
---|
| 515 | + "PoisonTLPBlocked", /* Bit Position 26 */ |
---|
| 516 | + NULL, /* Bit Position 27 */ |
---|
| 517 | + NULL, /* Bit Position 28 */ |
---|
| 518 | + NULL, /* Bit Position 29 */ |
---|
| 519 | + NULL, /* Bit Position 30 */ |
---|
| 520 | + NULL, /* Bit Position 31 */ |
---|
577 | 521 | }; |
---|
578 | 522 | |
---|
579 | 523 | static const char *aer_agent_string[] = { |
---|
.. | .. |
---|
594 | 538 | struct pci_dev *pdev = to_pci_dev(dev); \ |
---|
595 | 539 | u64 *stats = pdev->aer_stats->stats_array; \ |
---|
596 | 540 | \ |
---|
597 | | - for (i = 0; i < ARRAY_SIZE(strings_array); i++) { \ |
---|
| 541 | + for (i = 0; i < ARRAY_SIZE(pdev->aer_stats->stats_array); i++) {\ |
---|
598 | 542 | if (strings_array[i]) \ |
---|
599 | 543 | str += sprintf(str, "%s %llu\n", \ |
---|
600 | 544 | strings_array[i], stats[i]); \ |
---|
.. | .. |
---|
657 | 601 | if ((a == &dev_attr_aer_rootport_total_err_cor.attr || |
---|
658 | 602 | a == &dev_attr_aer_rootport_total_err_fatal.attr || |
---|
659 | 603 | a == &dev_attr_aer_rootport_total_err_nonfatal.attr) && |
---|
660 | | - pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) |
---|
| 604 | + ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) && |
---|
| 605 | + (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_EC))) |
---|
661 | 606 | return 0; |
---|
662 | 607 | |
---|
663 | 608 | return a->mode; |
---|
.. | .. |
---|
671 | 616 | static void pci_dev_aer_stats_incr(struct pci_dev *pdev, |
---|
672 | 617 | struct aer_err_info *info) |
---|
673 | 618 | { |
---|
674 | | - int status, i, max = -1; |
---|
| 619 | + unsigned long status = info->status & ~info->mask; |
---|
| 620 | + int i, max = -1; |
---|
675 | 621 | u64 *counter = NULL; |
---|
676 | 622 | struct aer_stats *aer_stats = pdev->aer_stats; |
---|
677 | 623 | |
---|
.. | .. |
---|
696 | 642 | break; |
---|
697 | 643 | } |
---|
698 | 644 | |
---|
699 | | - status = (info->status & ~info->mask); |
---|
700 | | - for (i = 0; i < max; i++) |
---|
701 | | - if (status & (1 << i)) |
---|
702 | | - counter[i]++; |
---|
| 645 | + for_each_set_bit(i, &status, max) |
---|
| 646 | + counter[i]++; |
---|
703 | 647 | } |
---|
704 | 648 | |
---|
705 | 649 | static void pci_rootport_aer_stats_incr(struct pci_dev *pdev, |
---|
.. | .. |
---|
731 | 675 | static void __aer_print_error(struct pci_dev *dev, |
---|
732 | 676 | struct aer_err_info *info) |
---|
733 | 677 | { |
---|
734 | | - int i, status; |
---|
735 | | - const char *errmsg = NULL; |
---|
736 | | - status = (info->status & ~info->mask); |
---|
| 678 | + const char **strings; |
---|
| 679 | + unsigned long status = info->status & ~info->mask; |
---|
| 680 | + const char *level, *errmsg; |
---|
| 681 | + int i; |
---|
737 | 682 | |
---|
738 | | - for (i = 0; i < 32; i++) { |
---|
739 | | - if (!(status & (1 << i))) |
---|
740 | | - continue; |
---|
| 683 | + if (info->severity == AER_CORRECTABLE) { |
---|
| 684 | + strings = aer_correctable_error_string; |
---|
| 685 | + level = KERN_WARNING; |
---|
| 686 | + } else { |
---|
| 687 | + strings = aer_uncorrectable_error_string; |
---|
| 688 | + level = KERN_ERR; |
---|
| 689 | + } |
---|
741 | 690 | |
---|
742 | | - if (info->severity == AER_CORRECTABLE) |
---|
743 | | - errmsg = i < ARRAY_SIZE(aer_correctable_error_string) ? |
---|
744 | | - aer_correctable_error_string[i] : NULL; |
---|
745 | | - else |
---|
746 | | - errmsg = i < ARRAY_SIZE(aer_uncorrectable_error_string) ? |
---|
747 | | - aer_uncorrectable_error_string[i] : NULL; |
---|
| 691 | + for_each_set_bit(i, &status, 32) { |
---|
| 692 | + errmsg = strings[i]; |
---|
| 693 | + if (!errmsg) |
---|
| 694 | + errmsg = "Unknown Error Bit"; |
---|
748 | 695 | |
---|
749 | | - if (errmsg) |
---|
750 | | - pci_err(dev, " [%2d] %-22s%s\n", i, errmsg, |
---|
| 696 | + pci_printk(level, dev, " [%2d] %-22s%s\n", i, errmsg, |
---|
751 | 697 | info->first_error == i ? " (First)" : ""); |
---|
752 | | - else |
---|
753 | | - pci_err(dev, " [%2d] Unknown Error Bit%s\n", |
---|
754 | | - i, info->first_error == i ? " (First)" : ""); |
---|
755 | 698 | } |
---|
756 | 699 | pci_dev_aer_stats_incr(dev, info); |
---|
757 | 700 | } |
---|
.. | .. |
---|
760 | 703 | { |
---|
761 | 704 | int layer, agent; |
---|
762 | 705 | int id = ((dev->bus->number << 8) | dev->devfn); |
---|
| 706 | + const char *level; |
---|
763 | 707 | |
---|
764 | 708 | if (!info->status) { |
---|
765 | 709 | pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n", |
---|
.. | .. |
---|
770 | 714 | layer = AER_GET_LAYER_ERROR(info->severity, info->status); |
---|
771 | 715 | agent = AER_GET_AGENT(info->severity, info->status); |
---|
772 | 716 | |
---|
773 | | - pci_err(dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n", |
---|
774 | | - aer_error_severity_string[info->severity], |
---|
775 | | - aer_error_layer[layer], aer_agent_string[agent]); |
---|
| 717 | + level = (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR; |
---|
776 | 718 | |
---|
777 | | - pci_err(dev, " device [%04x:%04x] error status/mask=%08x/%08x\n", |
---|
778 | | - dev->vendor, dev->device, |
---|
779 | | - info->status, info->mask); |
---|
| 719 | + pci_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n", |
---|
| 720 | + aer_error_severity_string[info->severity], |
---|
| 721 | + aer_error_layer[layer], aer_agent_string[agent]); |
---|
| 722 | + |
---|
| 723 | + pci_printk(level, dev, " device [%04x:%04x] error status/mask=%08x/%08x\n", |
---|
| 724 | + dev->vendor, dev->device, info->status, info->mask); |
---|
780 | 725 | |
---|
781 | 726 | __aer_print_error(dev, info); |
---|
782 | 727 | |
---|
.. | .. |
---|
796 | 741 | u8 bus = info->id >> 8; |
---|
797 | 742 | u8 devfn = info->id & 0xff; |
---|
798 | 743 | |
---|
799 | | - pci_info(dev, "AER: %s%s error received: %04x:%02x:%02x.%d\n", |
---|
800 | | - info->multi_error_valid ? "Multiple " : "", |
---|
801 | | - aer_error_severity_string[info->severity], |
---|
802 | | - pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); |
---|
| 744 | + pci_info(dev, "%s%s error received: %04x:%02x:%02x.%d\n", |
---|
| 745 | + info->multi_error_valid ? "Multiple " : "", |
---|
| 746 | + aer_error_severity_string[info->severity], |
---|
| 747 | + pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn), |
---|
| 748 | + PCI_FUNC(devfn)); |
---|
803 | 749 | } |
---|
804 | 750 | |
---|
805 | 751 | #ifdef CONFIG_ACPI_APEI_PCIEAER |
---|
.. | .. |
---|
880 | 826 | */ |
---|
881 | 827 | static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info) |
---|
882 | 828 | { |
---|
883 | | - int pos; |
---|
| 829 | + int aer = dev->aer_cap; |
---|
884 | 830 | u32 status, mask; |
---|
885 | 831 | u16 reg16; |
---|
886 | 832 | |
---|
.. | .. |
---|
915 | 861 | if (!(reg16 & PCI_EXP_AER_FLAGS)) |
---|
916 | 862 | return false; |
---|
917 | 863 | |
---|
918 | | - pos = dev->aer_cap; |
---|
919 | | - if (!pos) |
---|
| 864 | + if (!aer) |
---|
920 | 865 | return false; |
---|
921 | 866 | |
---|
922 | 867 | /* Check if error is recorded */ |
---|
923 | 868 | if (e_info->severity == AER_CORRECTABLE) { |
---|
924 | | - pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); |
---|
925 | | - pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &mask); |
---|
| 869 | + pci_read_config_dword(dev, aer + PCI_ERR_COR_STATUS, &status); |
---|
| 870 | + pci_read_config_dword(dev, aer + PCI_ERR_COR_MASK, &mask); |
---|
926 | 871 | } else { |
---|
927 | | - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); |
---|
928 | | - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &mask); |
---|
| 872 | + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, &status); |
---|
| 873 | + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, &mask); |
---|
929 | 874 | } |
---|
930 | 875 | if (status & ~mask) |
---|
931 | 876 | return true; |
---|
.. | .. |
---|
981 | 926 | pci_walk_bus(parent->subordinate, find_device_iter, e_info); |
---|
982 | 927 | |
---|
983 | 928 | if (!e_info->error_dev_num) { |
---|
984 | | - pci_printk(KERN_DEBUG, parent, "can't find device of ID%04x\n", |
---|
985 | | - e_info->id); |
---|
| 929 | + pci_info(parent, "can't find device of ID%04x\n", e_info->id); |
---|
986 | 930 | return false; |
---|
987 | 931 | } |
---|
988 | 932 | return true; |
---|
.. | .. |
---|
997 | 941 | */ |
---|
998 | 942 | static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info) |
---|
999 | 943 | { |
---|
1000 | | - int pos; |
---|
| 944 | + int aer = dev->aer_cap; |
---|
1001 | 945 | |
---|
1002 | 946 | if (info->severity == AER_CORRECTABLE) { |
---|
1003 | 947 | /* |
---|
1004 | 948 | * Correctable error does not need software intervention. |
---|
1005 | 949 | * No need to go through error recovery process. |
---|
1006 | 950 | */ |
---|
1007 | | - pos = dev->aer_cap; |
---|
1008 | | - if (pos) |
---|
1009 | | - pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, |
---|
| 951 | + if (aer) |
---|
| 952 | + pci_write_config_dword(dev, aer + PCI_ERR_COR_STATUS, |
---|
1010 | 953 | info->status); |
---|
1011 | | - pci_aer_clear_device_status(dev); |
---|
| 954 | + if (pcie_aer_is_native(dev)) |
---|
| 955 | + pcie_clear_device_status(dev); |
---|
1012 | 956 | } else if (info->severity == AER_NONFATAL) |
---|
1013 | | - pcie_do_nonfatal_recovery(dev); |
---|
| 957 | + pcie_do_recovery(dev, pci_channel_io_normal, aer_root_reset); |
---|
1014 | 958 | else if (info->severity == AER_FATAL) |
---|
1015 | | - pcie_do_fatal_recovery(dev, PCIE_PORT_SERVICE_AER); |
---|
| 959 | + pcie_do_recovery(dev, pci_channel_io_frozen, aer_root_reset); |
---|
1016 | 960 | pci_dev_put(dev); |
---|
1017 | 961 | } |
---|
1018 | 962 | |
---|
.. | .. |
---|
1048 | 992 | } |
---|
1049 | 993 | cper_print_aer(pdev, entry.severity, entry.regs); |
---|
1050 | 994 | if (entry.severity == AER_NONFATAL) |
---|
1051 | | - pcie_do_nonfatal_recovery(pdev); |
---|
| 995 | + pcie_do_recovery(pdev, pci_channel_io_normal, |
---|
| 996 | + aer_root_reset); |
---|
1052 | 997 | else if (entry.severity == AER_FATAL) |
---|
1053 | | - pcie_do_fatal_recovery(pdev, PCIE_PORT_SERVICE_AER); |
---|
| 998 | + pcie_do_recovery(pdev, pci_channel_io_frozen, |
---|
| 999 | + aer_root_reset); |
---|
1054 | 1000 | pci_dev_put(pdev); |
---|
1055 | 1001 | } |
---|
1056 | 1002 | } |
---|
.. | .. |
---|
1066 | 1012 | void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, |
---|
1067 | 1013 | int severity, struct aer_capability_regs *aer_regs) |
---|
1068 | 1014 | { |
---|
1069 | | - unsigned long flags; |
---|
1070 | 1015 | struct aer_recover_entry entry = { |
---|
1071 | 1016 | .bus = bus, |
---|
1072 | 1017 | .devfn = devfn, |
---|
.. | .. |
---|
1075 | 1020 | .regs = aer_regs, |
---|
1076 | 1021 | }; |
---|
1077 | 1022 | |
---|
1078 | | - spin_lock_irqsave(&aer_recover_ring_lock, flags); |
---|
1079 | | - if (kfifo_put(&aer_recover_ring, entry)) |
---|
| 1023 | + if (kfifo_in_spinlocked(&aer_recover_ring, &entry, 1, |
---|
| 1024 | + &aer_recover_ring_lock)) |
---|
1080 | 1025 | schedule_work(&aer_recover_work); |
---|
1081 | 1026 | else |
---|
1082 | 1027 | pr_err("AER recover: Buffer overflow when recovering AER for %04x:%02x:%02x:%x\n", |
---|
1083 | 1028 | domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); |
---|
1084 | | - spin_unlock_irqrestore(&aer_recover_ring_lock, flags); |
---|
1085 | 1029 | } |
---|
1086 | 1030 | EXPORT_SYMBOL_GPL(aer_recover_queue); |
---|
1087 | 1031 | #endif |
---|
.. | .. |
---|
1097 | 1041 | */ |
---|
1098 | 1042 | int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) |
---|
1099 | 1043 | { |
---|
1100 | | - int pos, temp; |
---|
| 1044 | + int type = pci_pcie_type(dev); |
---|
| 1045 | + int aer = dev->aer_cap; |
---|
| 1046 | + int temp; |
---|
1101 | 1047 | |
---|
1102 | 1048 | /* Must reset in this function */ |
---|
1103 | 1049 | info->status = 0; |
---|
1104 | 1050 | info->tlp_header_valid = 0; |
---|
1105 | 1051 | |
---|
1106 | | - pos = dev->aer_cap; |
---|
1107 | | - |
---|
1108 | 1052 | /* The device might not support AER */ |
---|
1109 | | - if (!pos) |
---|
| 1053 | + if (!aer) |
---|
1110 | 1054 | return 0; |
---|
1111 | 1055 | |
---|
1112 | 1056 | if (info->severity == AER_CORRECTABLE) { |
---|
1113 | | - pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, |
---|
| 1057 | + pci_read_config_dword(dev, aer + PCI_ERR_COR_STATUS, |
---|
1114 | 1058 | &info->status); |
---|
1115 | | - pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, |
---|
| 1059 | + pci_read_config_dword(dev, aer + PCI_ERR_COR_MASK, |
---|
1116 | 1060 | &info->mask); |
---|
1117 | 1061 | if (!(info->status & ~info->mask)) |
---|
1118 | 1062 | return 0; |
---|
1119 | | - } else if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || |
---|
1120 | | - pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || |
---|
| 1063 | + } else if (type == PCI_EXP_TYPE_ROOT_PORT || |
---|
| 1064 | + type == PCI_EXP_TYPE_DOWNSTREAM || |
---|
1121 | 1065 | info->severity == AER_NONFATAL) { |
---|
1122 | 1066 | |
---|
1123 | 1067 | /* Link is still healthy for IO reads */ |
---|
1124 | | - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, |
---|
| 1068 | + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, |
---|
1125 | 1069 | &info->status); |
---|
1126 | | - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, |
---|
| 1070 | + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, |
---|
1127 | 1071 | &info->mask); |
---|
1128 | 1072 | if (!(info->status & ~info->mask)) |
---|
1129 | 1073 | return 0; |
---|
1130 | 1074 | |
---|
1131 | 1075 | /* Get First Error Pointer */ |
---|
1132 | | - pci_read_config_dword(dev, pos + PCI_ERR_CAP, &temp); |
---|
| 1076 | + pci_read_config_dword(dev, aer + PCI_ERR_CAP, &temp); |
---|
1133 | 1077 | info->first_error = PCI_ERR_CAP_FEP(temp); |
---|
1134 | 1078 | |
---|
1135 | 1079 | if (info->status & AER_LOG_TLP_MASKS) { |
---|
1136 | 1080 | info->tlp_header_valid = 1; |
---|
1137 | 1081 | pci_read_config_dword(dev, |
---|
1138 | | - pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0); |
---|
| 1082 | + aer + PCI_ERR_HEADER_LOG, &info->tlp.dw0); |
---|
1139 | 1083 | pci_read_config_dword(dev, |
---|
1140 | | - pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1); |
---|
| 1084 | + aer + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1); |
---|
1141 | 1085 | pci_read_config_dword(dev, |
---|
1142 | | - pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2); |
---|
| 1086 | + aer + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2); |
---|
1143 | 1087 | pci_read_config_dword(dev, |
---|
1144 | | - pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3); |
---|
| 1088 | + aer + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3); |
---|
1145 | 1089 | } |
---|
1146 | 1090 | } |
---|
1147 | 1091 | |
---|
.. | .. |
---|
1172 | 1116 | struct aer_err_source *e_src) |
---|
1173 | 1117 | { |
---|
1174 | 1118 | struct pci_dev *pdev = rpc->rpd; |
---|
1175 | | - struct aer_err_info *e_info = &rpc->e_info; |
---|
| 1119 | + struct aer_err_info e_info; |
---|
1176 | 1120 | |
---|
1177 | 1121 | pci_rootport_aer_stats_incr(pdev, e_src); |
---|
1178 | 1122 | |
---|
.. | .. |
---|
1181 | 1125 | * uncorrectable error being logged. Report correctable error first. |
---|
1182 | 1126 | */ |
---|
1183 | 1127 | if (e_src->status & PCI_ERR_ROOT_COR_RCV) { |
---|
1184 | | - e_info->id = ERR_COR_ID(e_src->id); |
---|
1185 | | - e_info->severity = AER_CORRECTABLE; |
---|
| 1128 | + e_info.id = ERR_COR_ID(e_src->id); |
---|
| 1129 | + e_info.severity = AER_CORRECTABLE; |
---|
1186 | 1130 | |
---|
1187 | 1131 | if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV) |
---|
1188 | | - e_info->multi_error_valid = 1; |
---|
| 1132 | + e_info.multi_error_valid = 1; |
---|
1189 | 1133 | else |
---|
1190 | | - e_info->multi_error_valid = 0; |
---|
1191 | | - aer_print_port_info(pdev, e_info); |
---|
| 1134 | + e_info.multi_error_valid = 0; |
---|
| 1135 | + aer_print_port_info(pdev, &e_info); |
---|
1192 | 1136 | |
---|
1193 | | - if (find_source_device(pdev, e_info)) |
---|
1194 | | - aer_process_err_devices(e_info); |
---|
| 1137 | + if (find_source_device(pdev, &e_info)) |
---|
| 1138 | + aer_process_err_devices(&e_info); |
---|
1195 | 1139 | } |
---|
1196 | 1140 | |
---|
1197 | 1141 | if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) { |
---|
1198 | | - e_info->id = ERR_UNCOR_ID(e_src->id); |
---|
| 1142 | + e_info.id = ERR_UNCOR_ID(e_src->id); |
---|
1199 | 1143 | |
---|
1200 | 1144 | if (e_src->status & PCI_ERR_ROOT_FATAL_RCV) |
---|
1201 | | - e_info->severity = AER_FATAL; |
---|
| 1145 | + e_info.severity = AER_FATAL; |
---|
1202 | 1146 | else |
---|
1203 | | - e_info->severity = AER_NONFATAL; |
---|
| 1147 | + e_info.severity = AER_NONFATAL; |
---|
1204 | 1148 | |
---|
1205 | 1149 | if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV) |
---|
1206 | | - e_info->multi_error_valid = 1; |
---|
| 1150 | + e_info.multi_error_valid = 1; |
---|
1207 | 1151 | else |
---|
1208 | | - e_info->multi_error_valid = 0; |
---|
| 1152 | + e_info.multi_error_valid = 0; |
---|
1209 | 1153 | |
---|
1210 | | - aer_print_port_info(pdev, e_info); |
---|
| 1154 | + aer_print_port_info(pdev, &e_info); |
---|
1211 | 1155 | |
---|
1212 | | - if (find_source_device(pdev, e_info)) |
---|
1213 | | - aer_process_err_devices(e_info); |
---|
| 1156 | + if (find_source_device(pdev, &e_info)) |
---|
| 1157 | + aer_process_err_devices(&e_info); |
---|
1214 | 1158 | } |
---|
1215 | | -} |
---|
1216 | | - |
---|
1217 | | -/** |
---|
1218 | | - * get_e_source - retrieve an error source |
---|
1219 | | - * @rpc: pointer to the root port which holds an error |
---|
1220 | | - * @e_src: pointer to store retrieved error source |
---|
1221 | | - * |
---|
1222 | | - * Return 1 if an error source is retrieved, otherwise 0. |
---|
1223 | | - * |
---|
1224 | | - * Invoked by DPC handler to consume an error. |
---|
1225 | | - */ |
---|
1226 | | -static int get_e_source(struct aer_rpc *rpc, struct aer_err_source *e_src) |
---|
1227 | | -{ |
---|
1228 | | - unsigned long flags; |
---|
1229 | | - |
---|
1230 | | - /* Lock access to Root error producer/consumer index */ |
---|
1231 | | - spin_lock_irqsave(&rpc->e_lock, flags); |
---|
1232 | | - if (rpc->prod_idx == rpc->cons_idx) { |
---|
1233 | | - spin_unlock_irqrestore(&rpc->e_lock, flags); |
---|
1234 | | - return 0; |
---|
1235 | | - } |
---|
1236 | | - |
---|
1237 | | - *e_src = rpc->e_sources[rpc->cons_idx]; |
---|
1238 | | - rpc->cons_idx++; |
---|
1239 | | - if (rpc->cons_idx == AER_ERROR_SOURCES_MAX) |
---|
1240 | | - rpc->cons_idx = 0; |
---|
1241 | | - spin_unlock_irqrestore(&rpc->e_lock, flags); |
---|
1242 | | - |
---|
1243 | | - return 1; |
---|
1244 | 1159 | } |
---|
1245 | 1160 | |
---|
1246 | 1161 | /** |
---|
1247 | 1162 | * aer_isr - consume errors detected by root port |
---|
1248 | | - * @work: definition of this work item |
---|
| 1163 | + * @irq: IRQ assigned to Root Port |
---|
| 1164 | + * @context: pointer to Root Port data structure |
---|
1249 | 1165 | * |
---|
1250 | 1166 | * Invoked, as DPC, when root port records new detected error |
---|
1251 | 1167 | */ |
---|
1252 | | -static void aer_isr(struct work_struct *work) |
---|
| 1168 | +static irqreturn_t aer_isr(int irq, void *context) |
---|
1253 | 1169 | { |
---|
1254 | | - struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler); |
---|
1255 | | - struct aer_err_source uninitialized_var(e_src); |
---|
| 1170 | + struct pcie_device *dev = (struct pcie_device *)context; |
---|
| 1171 | + struct aer_rpc *rpc = get_service_data(dev); |
---|
| 1172 | + struct aer_err_source e_src; |
---|
1256 | 1173 | |
---|
1257 | | - mutex_lock(&rpc->rpc_mutex); |
---|
1258 | | - while (get_e_source(rpc, &e_src)) |
---|
| 1174 | + if (kfifo_is_empty(&rpc->aer_fifo)) |
---|
| 1175 | + return IRQ_NONE; |
---|
| 1176 | + |
---|
| 1177 | + while (kfifo_get(&rpc->aer_fifo, &e_src)) |
---|
1259 | 1178 | aer_isr_one_error(rpc, &e_src); |
---|
1260 | | - mutex_unlock(&rpc->rpc_mutex); |
---|
| 1179 | + return IRQ_HANDLED; |
---|
1261 | 1180 | } |
---|
1262 | 1181 | |
---|
1263 | 1182 | /** |
---|
.. | .. |
---|
1267 | 1186 | * |
---|
1268 | 1187 | * Invoked when Root Port detects AER messages. |
---|
1269 | 1188 | */ |
---|
1270 | | -irqreturn_t aer_irq(int irq, void *context) |
---|
| 1189 | +static irqreturn_t aer_irq(int irq, void *context) |
---|
1271 | 1190 | { |
---|
1272 | | - unsigned int status, id; |
---|
1273 | 1191 | struct pcie_device *pdev = (struct pcie_device *)context; |
---|
1274 | 1192 | struct aer_rpc *rpc = get_service_data(pdev); |
---|
1275 | | - int next_prod_idx; |
---|
1276 | | - unsigned long flags; |
---|
1277 | | - int pos; |
---|
| 1193 | + struct pci_dev *rp = rpc->rpd; |
---|
| 1194 | + int aer = rp->aer_cap; |
---|
| 1195 | + struct aer_err_source e_src = {}; |
---|
1278 | 1196 | |
---|
1279 | | - pos = pdev->port->aer_cap; |
---|
1280 | | - /* |
---|
1281 | | - * Must lock access to Root Error Status Reg, Root Error ID Reg, |
---|
1282 | | - * and Root error producer/consumer index |
---|
1283 | | - */ |
---|
1284 | | - spin_lock_irqsave(&rpc->e_lock, flags); |
---|
1285 | | - |
---|
1286 | | - /* Read error status */ |
---|
1287 | | - pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status); |
---|
1288 | | - if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) { |
---|
1289 | | - spin_unlock_irqrestore(&rpc->e_lock, flags); |
---|
| 1197 | + pci_read_config_dword(rp, aer + PCI_ERR_ROOT_STATUS, &e_src.status); |
---|
| 1198 | + if (!(e_src.status & AER_ERR_STATUS_MASK)) |
---|
1290 | 1199 | return IRQ_NONE; |
---|
1291 | | - } |
---|
1292 | 1200 | |
---|
1293 | | - /* Read error source and clear error status */ |
---|
1294 | | - pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id); |
---|
1295 | | - pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status); |
---|
| 1201 | + pci_read_config_dword(rp, aer + PCI_ERR_ROOT_ERR_SRC, &e_src.id); |
---|
| 1202 | + pci_write_config_dword(rp, aer + PCI_ERR_ROOT_STATUS, e_src.status); |
---|
1296 | 1203 | |
---|
1297 | | - /* Store error source for later DPC handler */ |
---|
1298 | | - next_prod_idx = rpc->prod_idx + 1; |
---|
1299 | | - if (next_prod_idx == AER_ERROR_SOURCES_MAX) |
---|
1300 | | - next_prod_idx = 0; |
---|
1301 | | - if (next_prod_idx == rpc->cons_idx) { |
---|
1302 | | - /* |
---|
1303 | | - * Error Storm Condition - possibly the same error occurred. |
---|
1304 | | - * Drop the error. |
---|
1305 | | - */ |
---|
1306 | | - spin_unlock_irqrestore(&rpc->e_lock, flags); |
---|
| 1204 | + if (!kfifo_put(&rpc->aer_fifo, e_src)) |
---|
1307 | 1205 | return IRQ_HANDLED; |
---|
1308 | | - } |
---|
1309 | | - rpc->e_sources[rpc->prod_idx].status = status; |
---|
1310 | | - rpc->e_sources[rpc->prod_idx].id = id; |
---|
1311 | | - rpc->prod_idx = next_prod_idx; |
---|
1312 | | - spin_unlock_irqrestore(&rpc->e_lock, flags); |
---|
1313 | 1206 | |
---|
1314 | | - /* Invoke DPC handler */ |
---|
1315 | | - schedule_work(&rpc->dpc_handler); |
---|
1316 | | - |
---|
1317 | | - return IRQ_HANDLED; |
---|
| 1207 | + return IRQ_WAKE_THREAD; |
---|
1318 | 1208 | } |
---|
1319 | | -EXPORT_SYMBOL_GPL(aer_irq); |
---|
1320 | 1209 | |
---|
1321 | 1210 | static int set_device_error_reporting(struct pci_dev *dev, void *data) |
---|
1322 | 1211 | { |
---|
.. | .. |
---|
1324 | 1213 | int type = pci_pcie_type(dev); |
---|
1325 | 1214 | |
---|
1326 | 1215 | if ((type == PCI_EXP_TYPE_ROOT_PORT) || |
---|
| 1216 | + (type == PCI_EXP_TYPE_RC_EC) || |
---|
1327 | 1217 | (type == PCI_EXP_TYPE_UPSTREAM) || |
---|
1328 | 1218 | (type == PCI_EXP_TYPE_DOWNSTREAM)) { |
---|
1329 | 1219 | if (enable) |
---|
.. | .. |
---|
1362 | 1252 | static void aer_enable_rootport(struct aer_rpc *rpc) |
---|
1363 | 1253 | { |
---|
1364 | 1254 | struct pci_dev *pdev = rpc->rpd; |
---|
1365 | | - int aer_pos; |
---|
| 1255 | + int aer = pdev->aer_cap; |
---|
1366 | 1256 | u16 reg16; |
---|
1367 | 1257 | u32 reg32; |
---|
1368 | 1258 | |
---|
.. | .. |
---|
1374 | 1264 | pcie_capability_clear_word(pdev, PCI_EXP_RTCTL, |
---|
1375 | 1265 | SYSTEM_ERROR_INTR_ON_MESG_MASK); |
---|
1376 | 1266 | |
---|
1377 | | - aer_pos = pdev->aer_cap; |
---|
1378 | 1267 | /* Clear error status */ |
---|
1379 | | - pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, ®32); |
---|
1380 | | - pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32); |
---|
1381 | | - pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, ®32); |
---|
1382 | | - pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32); |
---|
1383 | | - pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, ®32); |
---|
1384 | | - pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32); |
---|
| 1268 | + pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, ®32); |
---|
| 1269 | + pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, reg32); |
---|
| 1270 | + pci_read_config_dword(pdev, aer + PCI_ERR_COR_STATUS, ®32); |
---|
| 1271 | + pci_write_config_dword(pdev, aer + PCI_ERR_COR_STATUS, reg32); |
---|
| 1272 | + pci_read_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, ®32); |
---|
| 1273 | + pci_write_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, reg32); |
---|
1385 | 1274 | |
---|
1386 | 1275 | /* |
---|
1387 | 1276 | * Enable error reporting for the root port device and downstream port |
---|
.. | .. |
---|
1390 | 1279 | set_downstream_devices_error_reporting(pdev, true); |
---|
1391 | 1280 | |
---|
1392 | 1281 | /* Enable Root Port's interrupt in response to error messages */ |
---|
1393 | | - pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, ®32); |
---|
| 1282 | + pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, ®32); |
---|
1394 | 1283 | reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; |
---|
1395 | | - pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32); |
---|
| 1284 | + pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32); |
---|
1396 | 1285 | } |
---|
1397 | 1286 | |
---|
1398 | 1287 | /** |
---|
.. | .. |
---|
1404 | 1293 | static void aer_disable_rootport(struct aer_rpc *rpc) |
---|
1405 | 1294 | { |
---|
1406 | 1295 | struct pci_dev *pdev = rpc->rpd; |
---|
| 1296 | + int aer = pdev->aer_cap; |
---|
1407 | 1297 | u32 reg32; |
---|
1408 | | - int pos; |
---|
1409 | 1298 | |
---|
1410 | 1299 | /* |
---|
1411 | 1300 | * Disable error reporting for the root port device and downstream port |
---|
.. | .. |
---|
1413 | 1302 | */ |
---|
1414 | 1303 | set_downstream_devices_error_reporting(pdev, false); |
---|
1415 | 1304 | |
---|
1416 | | - pos = pdev->aer_cap; |
---|
1417 | 1305 | /* Disable Root's interrupt in response to error messages */ |
---|
1418 | | - pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, ®32); |
---|
| 1306 | + pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, ®32); |
---|
1419 | 1307 | reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; |
---|
1420 | | - pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32); |
---|
| 1308 | + pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32); |
---|
1421 | 1309 | |
---|
1422 | 1310 | /* Clear Root's error status reg */ |
---|
1423 | | - pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, ®32); |
---|
1424 | | - pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32); |
---|
1425 | | -} |
---|
1426 | | - |
---|
1427 | | -/** |
---|
1428 | | - * aer_alloc_rpc - allocate Root Port data structure |
---|
1429 | | - * @dev: pointer to the pcie_dev data structure |
---|
1430 | | - * |
---|
1431 | | - * Invoked when Root Port's AER service is loaded. |
---|
1432 | | - */ |
---|
1433 | | -static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) |
---|
1434 | | -{ |
---|
1435 | | - struct aer_rpc *rpc; |
---|
1436 | | - |
---|
1437 | | - rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL); |
---|
1438 | | - if (!rpc) |
---|
1439 | | - return NULL; |
---|
1440 | | - |
---|
1441 | | - /* Initialize Root lock access, e_lock, to Root Error Status Reg */ |
---|
1442 | | - spin_lock_init(&rpc->e_lock); |
---|
1443 | | - |
---|
1444 | | - rpc->rpd = dev->port; |
---|
1445 | | - INIT_WORK(&rpc->dpc_handler, aer_isr); |
---|
1446 | | - mutex_init(&rpc->rpc_mutex); |
---|
1447 | | - |
---|
1448 | | - /* Use PCIe bus function to store rpc into PCIe device */ |
---|
1449 | | - set_service_data(dev, rpc); |
---|
1450 | | - |
---|
1451 | | - return rpc; |
---|
| 1311 | + pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, ®32); |
---|
| 1312 | + pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, reg32); |
---|
1452 | 1313 | } |
---|
1453 | 1314 | |
---|
1454 | 1315 | /** |
---|
.. | .. |
---|
1461 | 1322 | { |
---|
1462 | 1323 | struct aer_rpc *rpc = get_service_data(dev); |
---|
1463 | 1324 | |
---|
1464 | | - if (rpc) { |
---|
1465 | | - /* If register interrupt service, it must be free. */ |
---|
1466 | | - if (rpc->isr) |
---|
1467 | | - free_irq(dev->irq, dev); |
---|
1468 | | - |
---|
1469 | | - flush_work(&rpc->dpc_handler); |
---|
1470 | | - aer_disable_rootport(rpc); |
---|
1471 | | - kfree(rpc); |
---|
1472 | | - set_service_data(dev, NULL); |
---|
1473 | | - } |
---|
| 1325 | + aer_disable_rootport(rpc); |
---|
1474 | 1326 | } |
---|
1475 | 1327 | |
---|
1476 | 1328 | /** |
---|
.. | .. |
---|
1483 | 1335 | { |
---|
1484 | 1336 | int status; |
---|
1485 | 1337 | struct aer_rpc *rpc; |
---|
1486 | | - struct device *device = &dev->port->dev; |
---|
| 1338 | + struct device *device = &dev->device; |
---|
| 1339 | + struct pci_dev *port = dev->port; |
---|
1487 | 1340 | |
---|
1488 | | - /* Alloc rpc data structure */ |
---|
1489 | | - rpc = aer_alloc_rpc(dev); |
---|
1490 | | - if (!rpc) { |
---|
1491 | | - dev_printk(KERN_DEBUG, device, "alloc AER rpc failed\n"); |
---|
1492 | | - aer_remove(dev); |
---|
| 1341 | + BUILD_BUG_ON(ARRAY_SIZE(aer_correctable_error_string) < |
---|
| 1342 | + AER_MAX_TYPEOF_COR_ERRS); |
---|
| 1343 | + BUILD_BUG_ON(ARRAY_SIZE(aer_uncorrectable_error_string) < |
---|
| 1344 | + AER_MAX_TYPEOF_UNCOR_ERRS); |
---|
| 1345 | + |
---|
| 1346 | + /* Limit to Root Ports or Root Complex Event Collectors */ |
---|
| 1347 | + if ((pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC) && |
---|
| 1348 | + (pci_pcie_type(port) != PCI_EXP_TYPE_ROOT_PORT)) |
---|
| 1349 | + return -ENODEV; |
---|
| 1350 | + |
---|
| 1351 | + rpc = devm_kzalloc(device, sizeof(struct aer_rpc), GFP_KERNEL); |
---|
| 1352 | + if (!rpc) |
---|
1493 | 1353 | return -ENOMEM; |
---|
1494 | | - } |
---|
1495 | 1354 | |
---|
1496 | | - /* Request IRQ ISR */ |
---|
1497 | | - status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev); |
---|
| 1355 | + rpc->rpd = port; |
---|
| 1356 | + INIT_KFIFO(rpc->aer_fifo); |
---|
| 1357 | + set_service_data(dev, rpc); |
---|
| 1358 | + |
---|
| 1359 | + status = devm_request_threaded_irq(device, dev->irq, aer_irq, aer_isr, |
---|
| 1360 | + IRQF_SHARED, "aerdrv", dev); |
---|
1498 | 1361 | if (status) { |
---|
1499 | | - dev_printk(KERN_DEBUG, device, "request AER IRQ %d failed\n", |
---|
1500 | | - dev->irq); |
---|
1501 | | - aer_remove(dev); |
---|
| 1362 | + pci_err(port, "request AER IRQ %d failed\n", dev->irq); |
---|
1502 | 1363 | return status; |
---|
1503 | 1364 | } |
---|
1504 | 1365 | |
---|
1505 | | - rpc->isr = 1; |
---|
1506 | | - |
---|
1507 | 1366 | aer_enable_rootport(rpc); |
---|
1508 | | - dev_info(device, "AER enabled with IRQ %d\n", dev->irq); |
---|
| 1367 | + pci_info(port, "enabled with IRQ %d\n", dev->irq); |
---|
1509 | 1368 | return 0; |
---|
1510 | 1369 | } |
---|
1511 | 1370 | |
---|
1512 | 1371 | /** |
---|
1513 | | - * aer_root_reset - reset link on Root Port |
---|
1514 | | - * @dev: pointer to Root Port's pci_dev data structure |
---|
| 1372 | + * aer_root_reset - reset Root Port hierarchy or RCEC |
---|
| 1373 | + * @dev: pointer to Root Port or RCEC |
---|
1515 | 1374 | * |
---|
1516 | | - * Invoked by Port Bus driver when performing link reset at Root Port. |
---|
| 1375 | + * Invoked by Port Bus driver when performing reset. |
---|
1517 | 1376 | */ |
---|
1518 | 1377 | static pci_ers_result_t aer_root_reset(struct pci_dev *dev) |
---|
1519 | 1378 | { |
---|
| 1379 | + int type = pci_pcie_type(dev); |
---|
| 1380 | + struct pci_dev *root; |
---|
| 1381 | + int aer; |
---|
| 1382 | + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus); |
---|
1520 | 1383 | u32 reg32; |
---|
1521 | | - int pos; |
---|
1522 | 1384 | int rc; |
---|
1523 | 1385 | |
---|
1524 | | - pos = dev->aer_cap; |
---|
| 1386 | + root = dev; /* device with Root Error registers */ |
---|
| 1387 | + aer = root->aer_cap; |
---|
1525 | 1388 | |
---|
1526 | | - /* Disable Root's interrupt in response to error messages */ |
---|
1527 | | - pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ®32); |
---|
1528 | | - reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; |
---|
1529 | | - pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); |
---|
| 1389 | + if ((host->native_aer || pcie_ports_native) && aer) { |
---|
| 1390 | + /* Disable Root's interrupt in response to error messages */ |
---|
| 1391 | + pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, ®32); |
---|
| 1392 | + reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; |
---|
| 1393 | + pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32); |
---|
| 1394 | + } |
---|
1530 | 1395 | |
---|
1531 | | - rc = pci_bus_error_reset(dev); |
---|
1532 | | - pci_printk(KERN_DEBUG, dev, "Root Port link has been reset\n"); |
---|
| 1396 | + if (type == PCI_EXP_TYPE_RC_EC) { |
---|
| 1397 | + if (pcie_has_flr(dev)) { |
---|
| 1398 | + rc = pcie_flr(dev); |
---|
| 1399 | + pci_info(dev, "has been reset (%d)\n", rc); |
---|
| 1400 | + } else { |
---|
| 1401 | + pci_info(dev, "not reset (no FLR support)\n"); |
---|
| 1402 | + rc = -ENOTTY; |
---|
| 1403 | + } |
---|
| 1404 | + } else { |
---|
| 1405 | + rc = pci_bus_error_reset(dev); |
---|
| 1406 | + pci_info(dev, "Root Port link has been reset (%d)\n", rc); |
---|
| 1407 | + } |
---|
1533 | 1408 | |
---|
1534 | | - /* Clear Root Error Status */ |
---|
1535 | | - pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, ®32); |
---|
1536 | | - pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32); |
---|
| 1409 | + if ((host->native_aer || pcie_ports_native) && aer) { |
---|
| 1410 | + /* Clear Root Error Status */ |
---|
| 1411 | + pci_read_config_dword(root, aer + PCI_ERR_ROOT_STATUS, ®32); |
---|
| 1412 | + pci_write_config_dword(root, aer + PCI_ERR_ROOT_STATUS, reg32); |
---|
1537 | 1413 | |
---|
1538 | | - /* Enable Root Port's interrupt in response to error messages */ |
---|
1539 | | - pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ®32); |
---|
1540 | | - reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; |
---|
1541 | | - pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); |
---|
| 1414 | + /* Enable Root Port's interrupt in response to error messages */ |
---|
| 1415 | + pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, ®32); |
---|
| 1416 | + reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; |
---|
| 1417 | + pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32); |
---|
| 1418 | + } |
---|
1542 | 1419 | |
---|
1543 | 1420 | return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; |
---|
1544 | 1421 | } |
---|
1545 | 1422 | |
---|
1546 | | -/** |
---|
1547 | | - * aer_error_resume - clean up corresponding error status bits |
---|
1548 | | - * @dev: pointer to Root Port's pci_dev data structure |
---|
1549 | | - * |
---|
1550 | | - * Invoked by Port Bus driver during nonfatal recovery. |
---|
1551 | | - */ |
---|
1552 | | -static void aer_error_resume(struct pci_dev *dev) |
---|
1553 | | -{ |
---|
1554 | | - pci_aer_clear_device_status(dev); |
---|
1555 | | - pci_cleanup_aer_uncorrect_error_status(dev); |
---|
1556 | | -} |
---|
1557 | | - |
---|
1558 | 1423 | static struct pcie_port_service_driver aerdriver = { |
---|
1559 | 1424 | .name = "aer", |
---|
1560 | | - .port_type = PCI_EXP_TYPE_ROOT_PORT, |
---|
| 1425 | + .port_type = PCIE_ANY_PORT, |
---|
1561 | 1426 | .service = PCIE_PORT_SERVICE_AER, |
---|
1562 | 1427 | |
---|
1563 | 1428 | .probe = aer_probe, |
---|
1564 | 1429 | .remove = aer_remove, |
---|
1565 | | - .error_resume = aer_error_resume, |
---|
1566 | | - .reset_link = aer_root_reset, |
---|
1567 | 1430 | }; |
---|
1568 | 1431 | |
---|
1569 | 1432 | /** |
---|
.. | .. |
---|
1573 | 1436 | */ |
---|
1574 | 1437 | int __init pcie_aer_init(void) |
---|
1575 | 1438 | { |
---|
1576 | | - if (!pci_aer_available() || aer_acpi_firmware_first()) |
---|
| 1439 | + if (!pci_aer_available()) |
---|
1577 | 1440 | return -ENXIO; |
---|
1578 | 1441 | return pcie_port_service_register(&aerdriver); |
---|
1579 | 1442 | } |
---|