Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/pci: improve error handling during interrupt deregistration

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>

authored by

Sebastian Ott and committed by
Martin Schwidefsky
4dfbd3ef 795818e8

+25 -16
+1 -1
arch/s390/include/asm/pci_insn.h
··· 76 76 u32 gd; 77 77 } __packed __aligned(8); 78 78 79 - int zpci_mod_fc(u64 req, struct zpci_fib *fib); 79 + u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status); 80 80 int zpci_refresh_trans(u64 fn, u64 addr, u64 range); 81 81 int zpci_load(u64 *data, u64 req, u64 offset); 82 82 int zpci_store(u64 data, u64 req, u64 offset);
+19 -10
arch/s390/pci/pci.c
··· 108 108 { 109 109 u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT); 110 110 struct zpci_fib fib = {0}; 111 + u8 status; 111 112 112 113 fib.isc = PCI_ISC; 113 114 fib.sum = 1; /* enable summary notifications */ ··· 118 117 fib.aisb = (unsigned long) zpci_aisb_iv->vector + (zdev->aisb/64)*8; 119 118 fib.aisbo = zdev->aisb & 63; 120 119 121 - return zpci_mod_fc(req, &fib); 120 + return zpci_mod_fc(req, &fib, &status) ? -EIO : 0; 121 + } 122 + 123 + /* Modify PCI: Unregister adapter interruptions */ 124 + static int zpci_clear_airq(struct zpci_dev *zdev) 125 + { 126 + u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_DEREG_INT); 127 + struct zpci_fib fib = {0}; 128 + u8 cc, status; 129 + 130 + cc = zpci_mod_fc(req, &fib, &status); 131 + if (cc == 3 || (cc == 1 && status == 24)) 132 + /* Function already gone or IRQs already deregistered. */ 133 + cc = 0; 134 + 135 + return cc ? -EIO : 0; 122 136 } 123 137 124 138 struct mod_pci_args { ··· 147 131 { 148 132 u64 req = ZPCI_CREATE_REQ(zdev->fh, dmaas, fn); 149 133 struct zpci_fib fib = {0}; 134 + u8 status; 150 135 151 136 fib.pba = args->base; 152 137 fib.pal = args->limit; 153 138 fib.iota = args->iota; 154 139 fib.fmb_addr = args->fmb_addr; 155 140 156 - return zpci_mod_fc(req, &fib); 141 + return zpci_mod_fc(req, &fib, &status) ? -EIO : 0; 157 142 } 158 143 159 144 /* Modify PCI: Register I/O address translation parameters */ ··· 174 157 struct mod_pci_args args = { 0, 0, 0, 0 }; 175 158 176 159 return mod_pci(zdev, ZPCI_MOD_FC_DEREG_IOAT, dmaas, &args); 177 - } 178 - 179 - /* Modify PCI: Unregister adapter interruptions */ 180 - static int zpci_clear_airq(struct zpci_dev *zdev) 181 - { 182 - struct mod_pci_args args = { 0, 0, 0, 0 }; 183 - 184 - return mod_pci(zdev, ZPCI_MOD_FC_DEREG_INT, 0, &args); 185 160 } 186 161 187 162 /* Modify PCI: Set PCI function measurement parameters */
+5 -5
arch/s390/pci/pci_insn.c
··· 40 40 return cc; 41 41 } 42 42 43 - int zpci_mod_fc(u64 req, struct zpci_fib *fib) 43 + u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status) 44 44 { 45 - u8 cc, status; 45 + u8 cc; 46 46 47 47 do { 48 - cc = __mpcifc(req, fib, &status); 48 + cc = __mpcifc(req, fib, status); 49 49 if (cc == 2) 50 50 msleep(ZPCI_INSN_BUSY_DELAY); 51 51 } while (cc == 2); 52 52 53 53 if (cc) 54 - zpci_err_insn(cc, status, req, 0); 54 + zpci_err_insn(cc, *status, req, 0); 55 55 56 - return (cc) ? -EIO : 0; 56 + return cc; 57 57 } 58 58 59 59 /* Refresh PCI Translations */