1 // SPDX-License-Identifier: GPL-2.0
3 * This file implements the error recovery as a core part of PCIe error
4 * reporting. When a PCIe error is delivered, an error message will be
5 * collected and printed to console, then, an error recovery procedure
6 * will be executed by following the PCI error recovery rules.
8 * Copyright (C) 2006 Intel Corp.
9 * Tom Long Nguyen (tom.l.nguyen@intel.com)
10 * Zhang Yanmin (yanmin.zhang@intel.com)
13 #define dev_fmt(fmt) "AER: " fmt
15 #include <linux/pci.h>
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/errno.h>
19 #include <linux/aer.h>
23 static pci_ers_result_t
merge_result(enum pci_ers_result orig
,
24 enum pci_ers_result
new)
26 if (new == PCI_ERS_RESULT_NO_AER_DRIVER
)
27 return PCI_ERS_RESULT_NO_AER_DRIVER
;
29 if (new == PCI_ERS_RESULT_NONE
)
33 case PCI_ERS_RESULT_CAN_RECOVER
:
34 case PCI_ERS_RESULT_RECOVERED
:
37 case PCI_ERS_RESULT_DISCONNECT
:
38 if (new == PCI_ERS_RESULT_NEED_RESET
)
39 orig
= PCI_ERS_RESULT_NEED_RESET
;
48 static int report_error_detected(struct pci_dev
*dev
,
49 enum pci_channel_state state
,
50 enum pci_ers_result
*result
)
52 pci_ers_result_t vote
;
53 const struct pci_error_handlers
*err_handler
;
55 device_lock(&dev
->dev
);
56 if (!pci_dev_set_io_state(dev
, state
) ||
58 !dev
->driver
->err_handler
||
59 !dev
->driver
->err_handler
->error_detected
) {
61 * If any device in the subtree does not have an error_detected
62 * callback, PCI_ERS_RESULT_NO_AER_DRIVER prevents subsequent
63 * error callbacks of "any" device in the subtree, and will
64 * exit in the disconnected error state.
66 if (dev
->hdr_type
!= PCI_HEADER_TYPE_BRIDGE
) {
67 vote
= PCI_ERS_RESULT_NO_AER_DRIVER
;
68 pci_info(dev
, "can't recover (no error_detected callback)\n");
70 vote
= PCI_ERS_RESULT_NONE
;
73 err_handler
= dev
->driver
->err_handler
;
74 vote
= err_handler
->error_detected(dev
, state
);
76 pci_uevent_ers(dev
, vote
);
77 *result
= merge_result(*result
, vote
);
78 device_unlock(&dev
->dev
);
82 static int report_frozen_detected(struct pci_dev
*dev
, void *data
)
84 return report_error_detected(dev
, pci_channel_io_frozen
, data
);
87 static int report_normal_detected(struct pci_dev
*dev
, void *data
)
89 return report_error_detected(dev
, pci_channel_io_normal
, data
);
92 static int report_mmio_enabled(struct pci_dev
*dev
, void *data
)
94 pci_ers_result_t vote
, *result
= data
;
95 const struct pci_error_handlers
*err_handler
;
97 device_lock(&dev
->dev
);
99 !dev
->driver
->err_handler
||
100 !dev
->driver
->err_handler
->mmio_enabled
)
103 err_handler
= dev
->driver
->err_handler
;
104 vote
= err_handler
->mmio_enabled(dev
);
105 *result
= merge_result(*result
, vote
);
107 device_unlock(&dev
->dev
);
111 static int report_slot_reset(struct pci_dev
*dev
, void *data
)
113 pci_ers_result_t vote
, *result
= data
;
114 const struct pci_error_handlers
*err_handler
;
116 device_lock(&dev
->dev
);
118 !dev
->driver
->err_handler
||
119 !dev
->driver
->err_handler
->slot_reset
)
122 err_handler
= dev
->driver
->err_handler
;
123 vote
= err_handler
->slot_reset(dev
);
124 *result
= merge_result(*result
, vote
);
126 device_unlock(&dev
->dev
);
130 static int report_resume(struct pci_dev
*dev
, void *data
)
132 const struct pci_error_handlers
*err_handler
;
134 device_lock(&dev
->dev
);
135 if (!pci_dev_set_io_state(dev
, pci_channel_io_normal
) ||
137 !dev
->driver
->err_handler
||
138 !dev
->driver
->err_handler
->resume
)
141 err_handler
= dev
->driver
->err_handler
;
142 err_handler
->resume(dev
);
144 pci_uevent_ers(dev
, PCI_ERS_RESULT_RECOVERED
);
145 device_unlock(&dev
->dev
);
149 pci_ers_result_t
pcie_do_recovery(struct pci_dev
*dev
,
150 enum pci_channel_state state
,
151 pci_ers_result_t (*reset_link
)(struct pci_dev
*pdev
))
153 pci_ers_result_t status
= PCI_ERS_RESULT_CAN_RECOVER
;
157 * Error recovery runs on all subordinates of the first downstream port.
158 * If the downstream port detected the error, it is cleared at the end.
160 if (!(pci_pcie_type(dev
) == PCI_EXP_TYPE_ROOT_PORT
||
161 pci_pcie_type(dev
) == PCI_EXP_TYPE_DOWNSTREAM
))
162 dev
= dev
->bus
->self
;
163 bus
= dev
->subordinate
;
165 pci_dbg(dev
, "broadcast error_detected message\n");
166 if (state
== pci_channel_io_frozen
) {
167 pci_walk_bus(bus
, report_frozen_detected
, &status
);
168 status
= reset_link(dev
);
169 if (status
!= PCI_ERS_RESULT_RECOVERED
) {
170 pci_warn(dev
, "link reset failed\n");
174 pci_walk_bus(bus
, report_normal_detected
, &status
);
177 if (status
== PCI_ERS_RESULT_CAN_RECOVER
) {
178 status
= PCI_ERS_RESULT_RECOVERED
;
179 pci_dbg(dev
, "broadcast mmio_enabled message\n");
180 pci_walk_bus(bus
, report_mmio_enabled
, &status
);
183 if (status
== PCI_ERS_RESULT_NEED_RESET
) {
185 * TODO: Should call platform-specific
186 * functions to reset slot before calling
187 * drivers' slot_reset callbacks?
189 status
= PCI_ERS_RESULT_RECOVERED
;
190 pci_dbg(dev
, "broadcast slot_reset message\n");
191 pci_walk_bus(bus
, report_slot_reset
, &status
);
194 if (status
!= PCI_ERS_RESULT_RECOVERED
)
197 pci_dbg(dev
, "broadcast resume message\n");
198 pci_walk_bus(bus
, report_resume
, &status
);
200 pci_aer_clear_device_status(dev
);
201 pci_aer_clear_nonfatal_status(dev
);
202 pci_info(dev
, "device recovery successful\n");
206 pci_uevent_ers(dev
, PCI_ERS_RESULT_DISCONNECT
);
208 /* TODO: Should kernel panic here? */
209 pci_info(dev
, "device recovery failed\n");