]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
s390/pci: improve error handling during interrupt deregistration
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Sat, 10 Jun 2017 11:54:44 +0000 (13:54 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 28 Jun 2017 05:32:08 +0000 (07:32 +0200)
When we ask a function to stop creating interrupts this may fail
due to the function being already gone (e.g. after hot-unplug).

Consequently we don't free associated resources like summary bits
and bit vectors used for irq processing. This could lead to
situations where we ran out of these resources and fail to setup
new interrupts.

The fix is to just ignore the errors in cases where we can be
sure no new interrupts are generated.

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>
arch/s390/include/asm/pci_insn.h
arch/s390/pci/pci.c
arch/s390/pci/pci_insn.c

index 649eb62c52b3784ec0214e47482b87442d3081dd..34abcf2757995cdcc69a397d60f61cd1e5804ad3 100644 (file)
@@ -76,7 +76,7 @@ struct zpci_fib {
        u32 gd;
 } __packed __aligned(8);
 
-int zpci_mod_fc(u64 req, struct zpci_fib *fib);
+u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status);
 int zpci_refresh_trans(u64 fn, u64 addr, u64 range);
 int zpci_load(u64 *data, u64 req, u64 offset);
 int zpci_store(u64 data, u64 req, u64 offset);
index 3dd9686c576a9520cfb717accdce6ff1f037e155..82f3e788b0be7bc86341f4ba9e7ab7443840768f 100644 (file)
@@ -108,6 +108,7 @@ static int zpci_set_airq(struct zpci_dev *zdev)
 {
        u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT);
        struct zpci_fib fib = {0};
+       u8 status;
 
        fib.isc = PCI_ISC;
        fib.sum = 1;            /* enable summary notifications */
@@ -117,7 +118,22 @@ static int zpci_set_airq(struct zpci_dev *zdev)
        fib.aisb = (unsigned long) zpci_aisb_iv->vector + (zdev->aisb/64)*8;
        fib.aisbo = zdev->aisb & 63;
 
-       return zpci_mod_fc(req, &fib);
+       return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
+}
+
+/* Modify PCI: Unregister adapter interruptions */
+static int zpci_clear_airq(struct zpci_dev *zdev)
+{
+       u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_DEREG_INT);
+       struct zpci_fib fib = {0};
+       u8 cc, status;
+
+       cc = zpci_mod_fc(req, &fib, &status);
+       if (cc == 3 || (cc == 1 && status == 24))
+               /* Function already gone or IRQs already deregistered. */
+               cc = 0;
+
+       return cc ? -EIO : 0;
 }
 
 struct mod_pci_args {
@@ -131,13 +147,14 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args
 {
        u64 req = ZPCI_CREATE_REQ(zdev->fh, dmaas, fn);
        struct zpci_fib fib = {0};
+       u8 status;
 
        fib.pba = args->base;
        fib.pal = args->limit;
        fib.iota = args->iota;
        fib.fmb_addr = args->fmb_addr;
 
-       return zpci_mod_fc(req, &fib);
+       return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
 }
 
 /* Modify PCI: Register I/O address translation parameters */
@@ -159,14 +176,6 @@ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
        return mod_pci(zdev, ZPCI_MOD_FC_DEREG_IOAT, dmaas, &args);
 }
 
-/* Modify PCI: Unregister adapter interruptions */
-static int zpci_clear_airq(struct zpci_dev *zdev)
-{
-       struct mod_pci_args args = { 0, 0, 0, 0 };
-
-       return mod_pci(zdev, ZPCI_MOD_FC_DEREG_INT, 0, &args);
-}
-
 /* Modify PCI: Set PCI function measurement parameters */
 int zpci_fmb_enable_device(struct zpci_dev *zdev)
 {
index fa8d7d4b97515836e0b2d25a1c858fc8b28eef37..ea34086c86744e0e19cd072f160592efa2d1c7fa 100644 (file)
@@ -40,20 +40,20 @@ static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
        return cc;
 }
 
-int zpci_mod_fc(u64 req, struct zpci_fib *fib)
+u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status)
 {
-       u8 cc, status;
+       u8 cc;
 
        do {
-               cc = __mpcifc(req, fib, &status);
+               cc = __mpcifc(req, fib, status);
                if (cc == 2)
                        msleep(ZPCI_INSN_BUSY_DELAY);
        } while (cc == 2);
 
        if (cc)
-               zpci_err_insn(cc, status, req, 0);
+               zpci_err_insn(cc, *status, req, 0);
 
-       return (cc) ? -EIO : 0;
+       return cc;
 }
 
 /* Refresh PCI Translations */