From: Sebastian Ott <sebott@linux.vnet.ibm.com>
Subject: s390/pci: don't cleanup in arch_setup_msi_irqs
Patch-mainline: v4.13-rc1
Git-commit: 795818e8bf17dbc791764ba9fb723278ee934676
References: bnc#1066983, LTC#157731
Description: PCI: fix hotplug related issues
Symptom: After serveral cycles of hot-unplug/hotplug the affected
function stops working or the kernel oopses.
Problem: Hotplug notifications happen after the fact, meaning it's
not possible to issue instructions to the function for
cleanup purposes. Thus we never release the associated
resources and at some point fail to allocate new ones.
Solution: During clean up treat some errors as success (e.g. a
function that's gone can't create an interrupt).
Reproduction: vmcp att pcif XXX to \* ;vmcp det pcif XXX #in a loop
Upstream-Description:
s390/pci: don't cleanup in arch_setup_msi_irqs
After failures in arch_setup_msi_irqs common code calls
arch_teardown_msi_irqs. Thus, remove cleanup code from
arch_setup_msi_irqs.
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Acked-by: Hannes Reinecke <hare@suse.com>
---
arch/s390/include/asm/pci.h | 2 -
arch/s390/pci/pci.c | 45 ++++++++++++++++----------------------------
2 files changed, 18 insertions(+), 29 deletions(-)
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -109,7 +109,7 @@ struct zpci_dev {
u64 msi_addr; /* MSI address */
unsigned int max_msi; /* maximum number of MSI's */
struct airq_iv *aibv; /* adapter interrupt bit vector */
- unsigned int aisb; /* number of the summary bit */
+ unsigned long aisb; /* number of the summary bit */
/* DMA stuff */
unsigned long *dma_table;
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -372,22 +372,21 @@ int arch_setup_msi_irqs(struct pci_dev *
struct msi_msg msg;
int rc, irq;
+ zdev->aisb = -1UL;
if (type == PCI_CAP_ID_MSI && nvec > 1)
return 1;
msi_vecs = min_t(unsigned int, nvec, zdev->max_msi);
/* Allocate adapter summary indicator bit */
- rc = -EIO;
aisb = airq_iv_alloc_bit(zpci_aisb_iv);
if (aisb == -1UL)
- goto out;
+ return -EIO;
zdev->aisb = aisb;
/* Create adapter interrupt vector */
- rc = -ENOMEM;
zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK);
if (!zdev->aibv)
- goto out_si;
+ return -ENOMEM;
/* Wire up shortcut pointer */
zpci_aibv[aisb] = zdev->aibv;
@@ -398,10 +397,10 @@ int arch_setup_msi_irqs(struct pci_dev *
rc = -EIO;
irq = irq_alloc_desc(0); /* Alloc irq on node 0 */
if (irq < 0)
- goto out_msi;
+ return -ENOMEM;
rc = irq_set_msi_desc(irq, msi);
if (rc)
- goto out_msi;
+ return rc;
irq_set_chip_and_handler(irq, &zpci_irq_chip,
handle_simple_irq);
msg.data = hwirq;
@@ -415,27 +414,9 @@ int arch_setup_msi_irqs(struct pci_dev *
/* Enable adapter interrupts */
rc = zpci_set_airq(zdev);
if (rc)
- goto out_msi;
+ return rc;
return (msi_vecs == nvec) ? 0 : msi_vecs;
-
-out_msi:
- for_each_pci_msi_entry(msi, pdev) {
- if (hwirq-- == 0)
- break;
- irq_set_msi_desc(msi->irq, NULL);
- irq_free_desc(msi->irq);
- msi->msg.address_lo = 0;
- msi->msg.address_hi = 0;
- msi->msg.data = 0;
- msi->irq = 0;
- }
- zpci_aibv[aisb] = NULL;
- airq_iv_release(zdev->aibv);
-out_si:
- airq_iv_free_bit(zpci_aisb_iv, aisb);
-out:
- return rc;
}
void arch_teardown_msi_irqs(struct pci_dev *pdev)
@@ -451,6 +432,8 @@ void arch_teardown_msi_irqs(struct pci_d
/* Release MSI interrupts */
for_each_pci_msi_entry(msi, pdev) {
+ if (!msi->irq)
+ continue;
if (msi->msi_attrib.is_msix)
__pci_msix_desc_mask_irq(msi, 1);
else
@@ -463,9 +446,15 @@ void arch_teardown_msi_irqs(struct pci_d
msi->irq = 0;
}
- zpci_aibv[zdev->aisb] = NULL;
- airq_iv_release(zdev->aibv);
- airq_iv_free_bit(zpci_aisb_iv, zdev->aisb);
+ if (zdev->aisb != -1UL) {
+ zpci_aibv[zdev->aisb] = NULL;
+ airq_iv_free_bit(zpci_aisb_iv, zdev->aisb);
+ zdev->aisb = -1UL;
+ }
+ if (zdev->aibv) {
+ airq_iv_release(zdev->aibv);
+ zdev->aibv = NULL;
+ }
}
static void zpci_map_resources(struct pci_dev *pdev)