| From bd1f46deba615971a58193afd0202878cadf19a7 Mon Sep 17 00:00:00 2001 |
| From: Andrew Patterson <andrew.patterson@hp.com> |
| Date: Fri, 22 Jan 2010 14:06:53 -0700 |
| Subject: PCI: fix nested spinlock hang in aer_inject |
| |
| From: Andrew Patterson <andrew.patterson@hp.com> |
| |
| 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> |
| |
| --- |
| drivers/pci/pcie/aer/aer_inject.c | 12 ++++++------ |
| 1 file changed, 6 insertions(+), 6 deletions(-) |
| |
| --- 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_i |
| 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_i |
| 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_i |
| 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"); |