diff options
| author | Prarit Bhargava <prarit@redhat.com> | 2011-01-11 15:34:35 -0500 |
|---|---|---|
| committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2011-03-04 13:41:02 -0500 |
| commit | 457d9d088b026e26dbab98cad9d299c1faf4c343 (patch) | |
| tree | 654406ce3724d90fe784446ef38c12605adb692e | |
| parent | 3449248c8731e8474980856d76bbf9bac9b0682f (diff) | |
PCI: aer-inject: Override PCIe AER Mask Registers
I have several systems which have the same problem: The PCIe AER
corrected and uncorrected masks have all the error bits set. This
results in the inablility to test with the aer_inject module & utility
on those systems.
Add the 'aer_mask_override' module parameter which will override the
corrected or uncorrected masks for a PCI device. The mask will have the
bit corresponding to the status passed into the aer_inject() function.
After this patch it is possible to successfully use the aer_inject
utility on those PCI slots.
Successfully tested by me on a Dell and Intel whitebox which exhibited
the mask problem.
Signed-off-by: Prarit Bhargava <prarit@redhat.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
| -rw-r--r-- | drivers/pci/pcie/aer/aer_inject.c | 31 |
1 files changed, 28 insertions, 3 deletions
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c index b3cf6223f63..f62079ff06d 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c | |||
| @@ -27,6 +27,10 @@ | |||
| 27 | #include <linux/stddef.h> | 27 | #include <linux/stddef.h> |
| 28 | #include "aerdrv.h" | 28 | #include "aerdrv.h" |
| 29 | 29 | ||
| 30 | /* Override the existing corrected and uncorrected error masks */ | ||
| 31 | static int aer_mask_override; | ||
| 32 | module_param(aer_mask_override, bool, 0); | ||
| 33 | |||
| 30 | struct aer_error_inj { | 34 | struct aer_error_inj { |
| 31 | u8 bus; | 35 | u8 bus; |
| 32 | u8 dev; | 36 | u8 dev; |
| @@ -322,7 +326,7 @@ static int aer_inject(struct aer_error_inj *einj) | |||
| 322 | unsigned long flags; | 326 | unsigned long flags; |
| 323 | unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); | 327 | unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); |
| 324 | int pos_cap_err, rp_pos_cap_err; | 328 | int pos_cap_err, rp_pos_cap_err; |
| 325 | u32 sever, cor_mask, uncor_mask; | 329 | u32 sever, cor_mask, uncor_mask, cor_mask_orig, uncor_mask_orig; |
| 326 | int ret = 0; | 330 | int ret = 0; |
| 327 | 331 | ||
| 328 | dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn); | 332 | dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn); |
| @@ -361,6 +365,18 @@ static int aer_inject(struct aer_error_inj *einj) | |||
| 361 | goto out_put; | 365 | goto out_put; |
| 362 | } | 366 | } |
| 363 | 367 | ||
| 368 | if (aer_mask_override) { | ||
| 369 | cor_mask_orig = cor_mask; | ||
| 370 | cor_mask &= !(einj->cor_status); | ||
| 371 | pci_write_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, | ||
| 372 | cor_mask); | ||
| 373 | |||
| 374 | uncor_mask_orig = uncor_mask; | ||
| 375 | uncor_mask &= !(einj->uncor_status); | ||
| 376 | pci_write_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, | ||
| 377 | uncor_mask); | ||
| 378 | } | ||
| 379 | |||
| 364 | spin_lock_irqsave(&inject_lock, flags); | 380 | spin_lock_irqsave(&inject_lock, flags); |
| 365 | 381 | ||
| 366 | err = __find_aer_error_by_dev(dev); | 382 | err = __find_aer_error_by_dev(dev); |
| @@ -378,14 +394,16 @@ static int aer_inject(struct aer_error_inj *einj) | |||
| 378 | err->header_log2 = einj->header_log2; | 394 | err->header_log2 = einj->header_log2; |
| 379 | err->header_log3 = einj->header_log3; | 395 | err->header_log3 = einj->header_log3; |
| 380 | 396 | ||
| 381 | if (einj->cor_status && !(einj->cor_status & ~cor_mask)) { | 397 | if (!aer_mask_override && einj->cor_status && |
| 398 | !(einj->cor_status & ~cor_mask)) { | ||
| 382 | ret = -EINVAL; | 399 | ret = -EINVAL; |
| 383 | printk(KERN_WARNING "The correctable error(s) is masked " | 400 | printk(KERN_WARNING "The correctable error(s) is masked " |
| 384 | "by device\n"); | 401 | "by device\n"); |
| 385 | spin_unlock_irqrestore(&inject_lock, flags); | 402 | spin_unlock_irqrestore(&inject_lock, flags); |
| 386 | goto out_put; | 403 | goto out_put; |
| 387 | } | 404 | } |
| 388 | if (einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) { | 405 | if (!aer_mask_override && einj->uncor_status && |
| 406 | !(einj->uncor_status & ~uncor_mask)) { | ||
| 389 | ret = -EINVAL; | 407 | ret = -EINVAL; |
| 390 | printk(KERN_WARNING "The uncorrectable error(s) is masked " | 408 | printk(KERN_WARNING "The uncorrectable error(s) is masked " |
| 391 | "by device\n"); | 409 | "by device\n"); |
| @@ -425,6 +443,13 @@ static int aer_inject(struct aer_error_inj *einj) | |||
| 425 | } | 443 | } |
| 426 | spin_unlock_irqrestore(&inject_lock, flags); | 444 | spin_unlock_irqrestore(&inject_lock, flags); |
| 427 | 445 | ||
| 446 | if (aer_mask_override) { | ||
| 447 | pci_write_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, | ||
| 448 | cor_mask_orig); | ||
| 449 | pci_write_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, | ||
| 450 | uncor_mask_orig); | ||
| 451 | } | ||
| 452 | |||
| 428 | ret = pci_bus_set_aer_ops(dev->bus); | 453 | ret = pci_bus_set_aer_ops(dev->bus); |
| 429 | if (ret) | 454 | if (ret) |
| 430 | goto out_put; | 455 | goto out_put; |
