1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/pci.h>
14#include <linux/module.h>
15#include <linux/pci.h>
16#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/aer.h>
19#include "portdrv.h"
20#include "../pci.h"
21
22struct aer_broadcast_data {
23 enum pci_channel_state state;
24 enum pci_ers_result result;
25};
26
27static pci_ers_result_t merge_result(enum pci_ers_result orig,
28 enum pci_ers_result new)
29{
30 if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
31 return PCI_ERS_RESULT_NO_AER_DRIVER;
32
33 if (new == PCI_ERS_RESULT_NONE)
34 return orig;
35
36 switch (orig) {
37 case PCI_ERS_RESULT_CAN_RECOVER:
38 case PCI_ERS_RESULT_RECOVERED:
39 orig = new;
40 break;
41 case PCI_ERS_RESULT_DISCONNECT:
42 if (new == PCI_ERS_RESULT_NEED_RESET)
43 orig = PCI_ERS_RESULT_NEED_RESET;
44 break;
45 default:
46 break;
47 }
48
49 return orig;
50}
51
52static int report_error_detected(struct pci_dev *dev, void *data)
53{
54 pci_ers_result_t vote;
55 const struct pci_error_handlers *err_handler;
56 struct aer_broadcast_data *result_data;
57
58 result_data = (struct aer_broadcast_data *) data;
59
60 device_lock(&dev->dev);
61 dev->error_state = result_data->state;
62
63 if (!dev->driver ||
64 !dev->driver->err_handler ||
65 !dev->driver->err_handler->error_detected) {
66 if (result_data->state == pci_channel_io_frozen &&
67 dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
68
69
70
71
72
73
74
75 pci_printk(KERN_DEBUG, dev, "device has %s\n",
76 dev->driver ?
77 "no AER-aware driver" : "no driver");
78 }
79
80
81
82
83
84
85
86
87
88
89
90 if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
91 vote = PCI_ERS_RESULT_NO_AER_DRIVER;
92 else
93 vote = PCI_ERS_RESULT_NONE;
94 } else {
95 err_handler = dev->driver->err_handler;
96 vote = err_handler->error_detected(dev, result_data->state);
97 pci_uevent_ers(dev, PCI_ERS_RESULT_NONE);
98 }
99
100 result_data->result = merge_result(result_data->result, vote);
101 device_unlock(&dev->dev);
102 return 0;
103}
104
105static int report_mmio_enabled(struct pci_dev *dev, void *data)
106{
107 pci_ers_result_t vote;
108 const struct pci_error_handlers *err_handler;
109 struct aer_broadcast_data *result_data;
110
111 result_data = (struct aer_broadcast_data *) data;
112
113 device_lock(&dev->dev);
114 if (!dev->driver ||
115 !dev->driver->err_handler ||
116 !dev->driver->err_handler->mmio_enabled)
117 goto out;
118
119 err_handler = dev->driver->err_handler;
120 vote = err_handler->mmio_enabled(dev);
121 result_data->result = merge_result(result_data->result, vote);
122out:
123 device_unlock(&dev->dev);
124 return 0;
125}
126
127static int report_slot_reset(struct pci_dev *dev, void *data)
128{
129 pci_ers_result_t vote;
130 const struct pci_error_handlers *err_handler;
131 struct aer_broadcast_data *result_data;
132
133 result_data = (struct aer_broadcast_data *) data;
134
135 device_lock(&dev->dev);
136 if (!dev->driver ||
137 !dev->driver->err_handler ||
138 !dev->driver->err_handler->slot_reset)
139 goto out;
140
141 err_handler = dev->driver->err_handler;
142 vote = err_handler->slot_reset(dev);
143 result_data->result = merge_result(result_data->result, vote);
144out:
145 device_unlock(&dev->dev);
146 return 0;
147}
148
149static int report_resume(struct pci_dev *dev, void *data)
150{
151 const struct pci_error_handlers *err_handler;
152
153 device_lock(&dev->dev);
154 dev->error_state = pci_channel_io_normal;
155
156 if (!dev->driver ||
157 !dev->driver->err_handler ||
158 !dev->driver->err_handler->resume)
159 goto out;
160
161 err_handler = dev->driver->err_handler;
162 err_handler->resume(dev);
163 pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED);
164out:
165 device_unlock(&dev->dev);
166 return 0;
167}
168
169
170
171
172
173
174
175
176static pci_ers_result_t default_reset_link(struct pci_dev *dev)
177{
178 int rc;
179
180 rc = pci_bridge_secondary_bus_reset(dev);
181 pci_printk(KERN_DEBUG, dev, "downstream link has been reset\n");
182 return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
183}
184
185static pci_ers_result_t reset_link(struct pci_dev *dev, u32 service)
186{
187 struct pci_dev *udev;
188 pci_ers_result_t status;
189 struct pcie_port_service_driver *driver = NULL;
190
191 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
192
193 udev = dev;
194 } else {
195
196 udev = dev->bus->self;
197 }
198
199
200 driver = pcie_port_find_service(udev, service);
201
202 if (driver && driver->reset_link) {
203 status = driver->reset_link(udev);
204 } else if (udev->has_secondary_link) {
205 status = default_reset_link(udev);
206 } else {
207 pci_printk(KERN_DEBUG, dev, "no link-reset support at upstream device %s\n",
208 pci_name(udev));
209 return PCI_ERS_RESULT_DISCONNECT;
210 }
211
212 if (status != PCI_ERS_RESULT_RECOVERED) {
213 pci_printk(KERN_DEBUG, dev, "link reset at upstream device %s failed\n",
214 pci_name(udev));
215 return PCI_ERS_RESULT_DISCONNECT;
216 }
217
218 return status;
219}
220
221
222
223
224
225
226
227
228
229
230
231
232static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
233 enum pci_channel_state state,
234 char *error_mesg,
235 int (*cb)(struct pci_dev *, void *))
236{
237 struct aer_broadcast_data result_data;
238
239 pci_printk(KERN_DEBUG, dev, "broadcast %s message\n", error_mesg);
240 result_data.state = state;
241 if (cb == report_error_detected)
242 result_data.result = PCI_ERS_RESULT_CAN_RECOVER;
243 else
244 result_data.result = PCI_ERS_RESULT_RECOVERED;
245
246 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
247
248
249
250
251
252
253 if (cb == report_error_detected)
254 dev->error_state = state;
255 pci_walk_bus(dev->subordinate, cb, &result_data);
256 if (cb == report_resume) {
257 pci_aer_clear_device_status(dev);
258 pci_cleanup_aer_uncorrect_error_status(dev);
259 dev->error_state = pci_channel_io_normal;
260 }
261 } else {
262
263
264
265
266
267
268 cb(dev, &result_data);
269 }
270
271 return result_data.result;
272}
273
274
275
276
277
278
279
280
281
282void pcie_do_fatal_recovery(struct pci_dev *dev, u32 service)
283{
284 struct pci_dev *udev;
285 struct pci_bus *parent;
286 struct pci_dev *pdev, *temp;
287 pci_ers_result_t result;
288
289 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
290 udev = dev;
291 else
292 udev = dev->bus->self;
293
294 parent = udev->subordinate;
295 pci_walk_bus(parent, pci_dev_set_disconnected, NULL);
296
297 pci_lock_rescan_remove();
298 pci_dev_get(dev);
299 list_for_each_entry_safe_reverse(pdev, temp, &parent->devices,
300 bus_list) {
301 pci_stop_and_remove_bus_device(pdev);
302 }
303
304 result = reset_link(udev, service);
305
306 if ((service == PCIE_PORT_SERVICE_AER) &&
307 (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
308
309
310
311
312
313
314 pci_aer_clear_fatal_status(dev);
315 pci_aer_clear_device_status(dev);
316 }
317
318 if (result == PCI_ERS_RESULT_RECOVERED) {
319 if (pcie_wait_for_link(udev, true))
320 pci_rescan_bus(udev->bus);
321 pci_info(dev, "Device recovery from fatal error successful\n");
322 } else {
323 pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT);
324 pci_info(dev, "Device recovery from fatal error failed\n");
325 }
326
327 pci_dev_put(dev);
328 pci_unlock_rescan_remove();
329}
330
331
332
333
334
335
336
337
338
339void pcie_do_nonfatal_recovery(struct pci_dev *dev)
340{
341 pci_ers_result_t status;
342 enum pci_channel_state state;
343
344 state = pci_channel_io_normal;
345
346 status = broadcast_error_message(dev,
347 state,
348 "error_detected",
349 report_error_detected);
350
351 if (status == PCI_ERS_RESULT_CAN_RECOVER)
352 status = broadcast_error_message(dev,
353 state,
354 "mmio_enabled",
355 report_mmio_enabled);
356
357 if (status == PCI_ERS_RESULT_NEED_RESET) {
358
359
360
361
362
363 status = broadcast_error_message(dev,
364 state,
365 "slot_reset",
366 report_slot_reset);
367 }
368
369 if (status != PCI_ERS_RESULT_RECOVERED)
370 goto failed;
371
372 broadcast_error_message(dev,
373 state,
374 "resume",
375 report_resume);
376
377 pci_info(dev, "AER: Device recovery successful\n");
378 return;
379
380failed:
381 pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT);
382
383
384 pci_info(dev, "AER: Device recovery failed\n");
385}
386