diff options
author | Andrew Patterson <andrew.patterson@hp.com> | 2010-01-22 14:06:53 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-04-26 07:41:31 -0700 |
commit | 90022a26dd2e166ae1ac3953d266ea42f083d65e (patch) | |
tree | 61f7b2257657b14e32b667d2b40950e4130298c8 | |
parent | 892cb6dc64b73037b756fd1b0014e8c2280ae28d (diff) |
PCI: fix nested spinlock hang in aer_inject
commit bd1f46deba615971a58193afd0202878cadf19a7 upstream.
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>
Cc: maximilian attems <max@stro.at>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/pci/pcie/aer/aer_inject.c | 12 |
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 0cd7ca18858..b8fb987e760 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c @@ -302,7 +302,7 @@ static int aer_inject(struct aer_error_inj *einj) unsigned long flags; unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); int pos_cap_err, rp_pos_cap_err; - u32 sever, mask; + u32 sever, cor_mask, uncor_mask; int ret = 0; dev = pci_get_bus_and_slot(einj->bus, devfn); @@ -320,6 +320,9 @@ static int aer_inject(struct aer_error_inj *einj) goto out_put; } pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever); + pci_read_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, &cor_mask); + pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, + &uncor_mask); rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR); if (!rp_pos_cap_err) { @@ -354,17 +357,14 @@ static int aer_inject(struct aer_error_inj *einj) err->header_log2 = einj->header_log2; err->header_log3 = einj->header_log3; - pci_read_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, &mask); - if (einj->cor_status && !(einj->cor_status & ~mask)) { + if (einj->cor_status && !(einj->cor_status & ~cor_mask)) { ret = -EINVAL; printk(KERN_WARNING "The correctable error(s) is masked " "by device\n"); spin_unlock_irqrestore(&inject_lock, flags); goto out_put; } - - pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, &mask); - if (einj->uncor_status && !(einj->uncor_status & ~mask)) { + if (einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) { ret = -EINVAL; printk(KERN_WARNING "The uncorrectable error(s) is masked " "by device\n"); |