Skip to content

Commit ba6a2f2

Browse files
committed
Merge tag 's390-6.16-4' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 fixes from Alexander Gordeev: - Fix PCI error recovery and bring it in line with AER/EEH * tag 's390-6.16-4' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/pci: Allow automatic recovery with minimal driver support s390/pci: Do not try re-enabling load/store if device is disabled s390/pci: Fix stale function handles in error handling
2 parents 3c894cb + 62355f1 commit ba6a2f2

File tree

1 file changed

+44
-15
lines changed

1 file changed

+44
-15
lines changed

arch/s390/pci/pci_event.c

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ static inline bool ers_result_indicates_abort(pci_ers_result_t ers_res)
5454
case PCI_ERS_RESULT_CAN_RECOVER:
5555
case PCI_ERS_RESULT_RECOVERED:
5656
case PCI_ERS_RESULT_NEED_RESET:
57+
case PCI_ERS_RESULT_NONE:
5758
return false;
5859
default:
5960
return true;
@@ -78,10 +79,6 @@ static bool is_driver_supported(struct pci_driver *driver)
7879
return false;
7980
if (!driver->err_handler->error_detected)
8081
return false;
81-
if (!driver->err_handler->slot_reset)
82-
return false;
83-
if (!driver->err_handler->resume)
84-
return false;
8582
return true;
8683
}
8784

@@ -106,6 +103,10 @@ static pci_ers_result_t zpci_event_do_error_state_clear(struct pci_dev *pdev,
106103
struct zpci_dev *zdev = to_zpci(pdev);
107104
int rc;
108105

106+
/* The underlying device may have been disabled by the event */
107+
if (!zdev_enabled(zdev))
108+
return PCI_ERS_RESULT_NEED_RESET;
109+
109110
pr_info("%s: Unblocking device access for examination\n", pci_name(pdev));
110111
rc = zpci_reset_load_store_blocked(zdev);
111112
if (rc) {
@@ -114,16 +115,18 @@ static pci_ers_result_t zpci_event_do_error_state_clear(struct pci_dev *pdev,
114115
return PCI_ERS_RESULT_NEED_RESET;
115116
}
116117

117-
if (driver->err_handler->mmio_enabled) {
118+
if (driver->err_handler->mmio_enabled)
118119
ers_res = driver->err_handler->mmio_enabled(pdev);
119-
if (ers_result_indicates_abort(ers_res)) {
120-
pr_info("%s: Automatic recovery failed after MMIO re-enable\n",
121-
pci_name(pdev));
122-
return ers_res;
123-
} else if (ers_res == PCI_ERS_RESULT_NEED_RESET) {
124-
pr_debug("%s: Driver needs reset to recover\n", pci_name(pdev));
125-
return ers_res;
126-
}
120+
else
121+
ers_res = PCI_ERS_RESULT_NONE;
122+
123+
if (ers_result_indicates_abort(ers_res)) {
124+
pr_info("%s: Automatic recovery failed after MMIO re-enable\n",
125+
pci_name(pdev));
126+
return ers_res;
127+
} else if (ers_res == PCI_ERS_RESULT_NEED_RESET) {
128+
pr_debug("%s: Driver needs reset to recover\n", pci_name(pdev));
129+
return ers_res;
127130
}
128131

129132
pr_debug("%s: Unblocking DMA\n", pci_name(pdev));
@@ -150,7 +153,12 @@ static pci_ers_result_t zpci_event_do_reset(struct pci_dev *pdev,
150153
return ers_res;
151154
}
152155
pdev->error_state = pci_channel_io_normal;
153-
ers_res = driver->err_handler->slot_reset(pdev);
156+
157+
if (driver->err_handler->slot_reset)
158+
ers_res = driver->err_handler->slot_reset(pdev);
159+
else
160+
ers_res = PCI_ERS_RESULT_NONE;
161+
154162
if (ers_result_indicates_abort(ers_res)) {
155163
pr_info("%s: Automatic recovery failed after slot reset\n", pci_name(pdev));
156164
return ers_res;
@@ -214,7 +222,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev)
214222
goto out_unlock;
215223
}
216224

217-
if (ers_res == PCI_ERS_RESULT_CAN_RECOVER) {
225+
if (ers_res != PCI_ERS_RESULT_NEED_RESET) {
218226
ers_res = zpci_event_do_error_state_clear(pdev, driver);
219227
if (ers_result_indicates_abort(ers_res)) {
220228
status_str = "failed (abort on MMIO enable)";
@@ -225,6 +233,16 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev)
225233
if (ers_res == PCI_ERS_RESULT_NEED_RESET)
226234
ers_res = zpci_event_do_reset(pdev, driver);
227235

236+
/*
237+
* ers_res can be PCI_ERS_RESULT_NONE either because the driver
238+
* decided to return it, indicating that it abstains from voting
239+
* on how to recover, or because it didn't implement the callback.
240+
* Both cases assume, that if there is nothing else causing a
241+
* disconnect, we recovered successfully.
242+
*/
243+
if (ers_res == PCI_ERS_RESULT_NONE)
244+
ers_res = PCI_ERS_RESULT_RECOVERED;
245+
228246
if (ers_res != PCI_ERS_RESULT_RECOVERED) {
229247
pr_err("%s: Automatic recovery failed; operator intervention is required\n",
230248
pci_name(pdev));
@@ -273,6 +291,8 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
273291
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
274292
struct pci_dev *pdev = NULL;
275293
pci_ers_result_t ers_res;
294+
u32 fh = 0;
295+
int rc;
276296

277297
zpci_dbg(3, "err fid:%x, fh:%x, pec:%x\n",
278298
ccdf->fid, ccdf->fh, ccdf->pec);
@@ -281,6 +301,15 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
281301

282302
if (zdev) {
283303
mutex_lock(&zdev->state_lock);
304+
rc = clp_refresh_fh(zdev->fid, &fh);
305+
if (rc)
306+
goto no_pdev;
307+
if (!fh || ccdf->fh != fh) {
308+
/* Ignore events with stale handles */
309+
zpci_dbg(3, "err fid:%x, fh:%x (stale %x)\n",
310+
ccdf->fid, fh, ccdf->fh);
311+
goto no_pdev;
312+
}
284313
zpci_update_fh(zdev, ccdf->fh);
285314
if (zdev->zbus->bus)
286315
pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);

0 commit comments

Comments
 (0)