aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorAndrew Patterson <andrew.patterson@hp.com>2010-01-22 16:06:53 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-01-25 13:42:52 -0500
commitbd1f46deba615971a58193afd0202878cadf19a7 (patch)
tree1a197e82ad0f6314f0ff0507c04030aaad933c7c /drivers/pci
parent61c39bb354a1f791ba6f562b766a72e508a036ee (diff)
PCI: fix nested spinlock hang in aer_inject
The aer_inject module hangs in aer_inject() when checking the device's error masks. The hang is due to a recursive use of the aer_inject lock. The aer_inject() routine grabs the lock while processing the error and then calls pci_read_config_dword to read the masks. The pci_read_config_dword routine is earlier overridden by pci_read_aer, which among other things, grabs the aer_inject lock. Fixed by moving the pci_read_config_dword calls to read the masks to before the lock is taken. Acked-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Andrew Patterson <andrew.patterson@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pcie/aer/aer_inject.c12
1 files changed, 6 insertions, 6 deletions
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c
index 8c30a9544d61..223052b73563 100644
--- a/drivers/pci/pcie/aer/aer_inject.c
+++ b/drivers/pci/pcie/aer/aer_inject.c
@@ -321,7 +321,7 @@ static int aer_inject(struct aer_error_inj *einj)
321 unsigned long flags; 321 unsigned long flags;
322 unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); 322 unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn);
323 int pos_cap_err, rp_pos_cap_err; 323 int pos_cap_err, rp_pos_cap_err;
324 u32 sever, mask; 324 u32 sever, cor_mask, uncor_mask;
325 int ret = 0; 325 int ret = 0;
326 326
327 dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn); 327 dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn);
@@ -339,6 +339,9 @@ static int aer_inject(struct aer_error_inj *einj)
339 goto out_put; 339 goto out_put;
340 } 340 }
341 pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever); 341 pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever);
342 pci_read_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, &cor_mask);
343 pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK,
344 &uncor_mask);
342 345
343 rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR); 346 rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);
344 if (!rp_pos_cap_err) { 347 if (!rp_pos_cap_err) {
@@ -374,17 +377,14 @@ static int aer_inject(struct aer_error_inj *einj)
374 err->header_log2 = einj->header_log2; 377 err->header_log2 = einj->header_log2;
375 err->header_log3 = einj->header_log3; 378 err->header_log3 = einj->header_log3;
376 379
377 pci_read_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, &mask); 380 if (einj->cor_status && !(einj->cor_status & ~cor_mask)) {
378 if (einj->cor_status && !(einj->cor_status & ~mask)) {
379 ret = -EINVAL; 381 ret = -EINVAL;
380 printk(KERN_WARNING "The correctable error(s) is masked " 382 printk(KERN_WARNING "The correctable error(s) is masked "
381 "by device\n"); 383 "by device\n");
382 spin_unlock_irqrestore(&inject_lock, flags); 384 spin_unlock_irqrestore(&inject_lock, flags);
383 goto out_put; 385 goto out_put;
384 } 386 }
385 387 if (einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) {
386 pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, &mask);
387 if (einj->uncor_status && !(einj->uncor_status & ~mask)) {
388 ret = -EINVAL; 388 ret = -EINVAL;
389 printk(KERN_WARNING "The uncorrectable error(s) is masked " 389 printk(KERN_WARNING "The uncorrectable error(s) is masked "
390 "by device\n"); 390 "by device\n");