PCI: use pci_find_ext_capability everywhere
[linux-2.6.git] / drivers / pci / pcie / aer / aerdrv_core.c
1 /*
2  * drivers/pci/pcie/aer/aerdrv_core.c
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file "COPYING" in the main directory of this archive
6  * for more details.
7  *
8  * This file implements the core part of PCI-Express AER. When an pci-express
9  * error is delivered, an error message will be collected and printed to
10  * console, then, an error recovery procedure will be executed by following
11  * the pci error recovery rules.
12  *
13  * Copyright (C) 2006 Intel Corp.
14  *      Tom Long Nguyen (tom.l.nguyen@intel.com)
15  *      Zhang Yanmin (yanmin.zhang@intel.com)
16  *
17  */
18
19 #include <linux/module.h>
20 #include <linux/pci.h>
21 #include <linux/kernel.h>
22 #include <linux/errno.h>
23 #include <linux/pm.h>
24 #include <linux/suspend.h>
25 #include <linux/delay.h>
26 #include "aerdrv.h"
27
28 static int forceload;
29 module_param(forceload, bool, 0);
30
31 int pci_enable_pcie_error_reporting(struct pci_dev *dev)
32 {
33         u16 reg16 = 0;
34         int pos;
35
36         pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
37         if (!pos)
38                 return -EIO;
39
40         pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
41         if (!pos)
42                 return -EIO;
43
44         pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
45         reg16 = reg16 |
46                 PCI_EXP_DEVCTL_CERE |
47                 PCI_EXP_DEVCTL_NFERE |
48                 PCI_EXP_DEVCTL_FERE |
49                 PCI_EXP_DEVCTL_URRE;
50         pci_write_config_word(dev, pos+PCI_EXP_DEVCTL,
51                         reg16);
52         return 0;
53 }
54
55 int pci_disable_pcie_error_reporting(struct pci_dev *dev)
56 {
57         u16 reg16 = 0;
58         int pos;
59
60         pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
61         if (!pos)
62                 return -EIO;
63
64         pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
65         reg16 = reg16 & ~(PCI_EXP_DEVCTL_CERE |
66                         PCI_EXP_DEVCTL_NFERE |
67                         PCI_EXP_DEVCTL_FERE |
68                         PCI_EXP_DEVCTL_URRE);
69         pci_write_config_word(dev, pos+PCI_EXP_DEVCTL,
70                         reg16);
71         return 0;
72 }
73
74 int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
75 {
76         int pos;
77         u32 status, mask;
78
79         pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
80         if (!pos)
81                 return -EIO;
82
83         pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
84         pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
85         if (dev->error_state == pci_channel_io_normal)
86                 status &= ~mask; /* Clear corresponding nonfatal bits */
87         else
88                 status &= mask; /* Clear corresponding fatal bits */
89         pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
90
91         return 0;
92 }
93
94 #if 0
95 int pci_cleanup_aer_correct_error_status(struct pci_dev *dev)
96 {
97         int pos;
98         u32 status;
99
100         pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
101         if (!pos)
102                 return -EIO;
103
104         pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status);
105         pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, status);
106
107         return 0;
108 }
109 #endif  /*  0  */
110
111 static int find_device_iter(struct device *device, void *data)
112 {
113         struct pci_dev *dev;
114         u16 id = *(unsigned long *)data;
115         u8 secondary, subordinate, d_bus = id >> 8;
116
117         if (device->bus == &pci_bus_type) {
118                 dev = to_pci_dev(device);
119                 if (id == ((dev->bus->number << 8) | dev->devfn)) {
120                         /*
121                          * Device ID match
122                          */
123                         *(unsigned long*)data = (unsigned long)device;
124                         return 1;
125                 }
126
127                 /*
128                  * If device is P2P, check if it is an upstream?
129                  */
130                 if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
131                         pci_read_config_byte(dev, PCI_SECONDARY_BUS,
132                                 &secondary);
133                         pci_read_config_byte(dev, PCI_SUBORDINATE_BUS,
134                                 &subordinate);
135                         if (d_bus >= secondary && d_bus <= subordinate) {
136                                 *(unsigned long*)data = (unsigned long)device;
137                                 return 1;
138                         }
139                 }
140         }
141
142         return 0;
143 }
144
145 /**
146  * find_source_device - search through device hierarchy for source device
147  * @parent: pointer to Root Port pci_dev data structure
148  * @id: device ID of agent who sends an error message to this Root Port
149  *
150  * Invoked when error is detected at the Root Port.
151  */
152 static struct device* find_source_device(struct pci_dev *parent, u16 id)
153 {
154         struct pci_dev *dev = parent;
155         struct device *device;
156         unsigned long device_addr;
157         int status;
158
159         /* Is Root Port an agent that sends error message? */
160         if (id == ((dev->bus->number << 8) | dev->devfn))
161                 return &dev->dev;
162
163         do {
164                 device_addr = id;
165                 if ((status = device_for_each_child(&dev->dev,
166                         &device_addr, find_device_iter))) {
167                         device = (struct device*)device_addr;
168                         dev = to_pci_dev(device);
169                         if (id == ((dev->bus->number << 8) | dev->devfn))
170                                 return device;
171                 }
172         }while (status);
173
174         return NULL;
175 }
176
177 static void report_error_detected(struct pci_dev *dev, void *data)
178 {
179         pci_ers_result_t vote;
180         struct pci_error_handlers *err_handler;
181         struct aer_broadcast_data *result_data;
182         result_data = (struct aer_broadcast_data *) data;
183
184         dev->error_state = result_data->state;
185
186         if (!dev->driver ||
187                 !dev->driver->err_handler ||
188                 !dev->driver->err_handler->error_detected) {
189                 if (result_data->state == pci_channel_io_frozen &&
190                         !(dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) {
191                         /*
192                          * In case of fatal recovery, if one of down-
193                          * stream device has no driver. We might be
194                          * unable to recover because a later insmod
195                          * of a driver for this device is unaware of
196                          * its hw state.
197                          */
198                         dev_printk(KERN_DEBUG, &dev->dev, "device has %s\n",
199                                    dev->driver ?
200                                    "no AER-aware driver" : "no driver");
201                 }
202                 return;
203         }
204
205         err_handler = dev->driver->err_handler;
206         vote = err_handler->error_detected(dev, result_data->state);
207         result_data->result = merge_result(result_data->result, vote);
208         return;
209 }
210
211 static void report_mmio_enabled(struct pci_dev *dev, void *data)
212 {
213         pci_ers_result_t vote;
214         struct pci_error_handlers *err_handler;
215         struct aer_broadcast_data *result_data;
216         result_data = (struct aer_broadcast_data *) data;
217
218         if (!dev->driver ||
219                 !dev->driver->err_handler ||
220                 !dev->driver->err_handler->mmio_enabled)
221                 return;
222
223         err_handler = dev->driver->err_handler;
224         vote = err_handler->mmio_enabled(dev);
225         result_data->result = merge_result(result_data->result, vote);
226         return;
227 }
228
229 static void report_slot_reset(struct pci_dev *dev, void *data)
230 {
231         pci_ers_result_t vote;
232         struct pci_error_handlers *err_handler;
233         struct aer_broadcast_data *result_data;
234         result_data = (struct aer_broadcast_data *) data;
235
236         if (!dev->driver ||
237                 !dev->driver->err_handler ||
238                 !dev->driver->err_handler->slot_reset)
239                 return;
240
241         err_handler = dev->driver->err_handler;
242         vote = err_handler->slot_reset(dev);
243         result_data->result = merge_result(result_data->result, vote);
244         return;
245 }
246
247 static void report_resume(struct pci_dev *dev, void *data)
248 {
249         struct pci_error_handlers *err_handler;
250
251         dev->error_state = pci_channel_io_normal;
252
253         if (!dev->driver ||
254                 !dev->driver->err_handler ||
255                 !dev->driver->err_handler->slot_reset)
256                 return;
257
258         err_handler = dev->driver->err_handler;
259         err_handler->resume(dev);
260         return;
261 }
262
263 /**
264  * broadcast_error_message - handle message broadcast to downstream drivers
265  * @dev: pointer to from where in a hierarchy message is broadcasted down
266  * @state: error state
267  * @error_mesg: message to print
268  * @cb: callback to be broadcasted
269  *
270  * Invoked during error recovery process. Once being invoked, the content
271  * of error severity will be broadcasted to all downstream drivers in a
272  * hierarchy in question.
273  */
274 static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
275         enum pci_channel_state state,
276         char *error_mesg,
277         void (*cb)(struct pci_dev *, void *))
278 {
279         struct aer_broadcast_data result_data;
280
281         dev_printk(KERN_DEBUG, &dev->dev, "broadcast %s message\n", error_mesg);
282         result_data.state = state;
283         if (cb == report_error_detected)
284                 result_data.result = PCI_ERS_RESULT_CAN_RECOVER;
285         else
286                 result_data.result = PCI_ERS_RESULT_RECOVERED;
287
288         if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
289                 /*
290                  * If the error is reported by a bridge, we think this error
291                  * is related to the downstream link of the bridge, so we
292                  * do error recovery on all subordinates of the bridge instead
293                  * of the bridge and clear the error status of the bridge.
294                  */
295                 if (cb == report_error_detected)
296                         dev->error_state = state;
297                 pci_walk_bus(dev->subordinate, cb, &result_data);
298                 if (cb == report_resume) {
299                         pci_cleanup_aer_uncorrect_error_status(dev);
300                         dev->error_state = pci_channel_io_normal;
301                 }
302         }
303         else {
304                 /*
305                  * If the error is reported by an end point, we think this
306                  * error is related to the upstream link of the end point.
307                  */
308                 pci_walk_bus(dev->bus, cb, &result_data);
309         }
310
311         return result_data.result;
312 }
313
314 struct find_aer_service_data {
315         struct pcie_port_service_driver *aer_driver;
316         int is_downstream;
317 };
318
319 static int find_aer_service_iter(struct device *device, void *data)
320 {
321         struct device_driver *driver;
322         struct pcie_port_service_driver *service_driver;
323         struct pcie_device *pcie_dev;
324         struct find_aer_service_data *result;
325
326         result = (struct find_aer_service_data *) data;
327
328         if (device->bus == &pcie_port_bus_type) {
329                 pcie_dev = to_pcie_device(device);
330                 if (pcie_dev->id.port_type == PCIE_SW_DOWNSTREAM_PORT)
331                         result->is_downstream = 1;
332
333                 driver = device->driver;
334                 if (driver) {
335                         service_driver = to_service_driver(driver);
336                         if (service_driver->id_table->service_type ==
337                                         PCIE_PORT_SERVICE_AER) {
338                                 result->aer_driver = service_driver;
339                                 return 1;
340                         }
341                 }
342         }
343
344         return 0;
345 }
346
347 static void find_aer_service(struct pci_dev *dev,
348                 struct find_aer_service_data *data)
349 {
350         int retval;
351         retval = device_for_each_child(&dev->dev, data, find_aer_service_iter);
352 }
353
354 static pci_ers_result_t reset_link(struct pcie_device *aerdev,
355                 struct pci_dev *dev)
356 {
357         struct pci_dev *udev;
358         pci_ers_result_t status;
359         struct find_aer_service_data data;
360
361         if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)
362                 udev = dev;
363         else
364                 udev= dev->bus->self;
365
366         data.is_downstream = 0;
367         data.aer_driver = NULL;
368         find_aer_service(udev, &data);
369
370         /*
371          * Use the aer driver of the error agent firstly.
372          * If it hasn't the aer driver, use the root port's
373          */
374         if (!data.aer_driver || !data.aer_driver->reset_link) {
375                 if (data.is_downstream &&
376                         aerdev->device.driver &&
377                         to_service_driver(aerdev->device.driver)->reset_link) {
378                         data.aer_driver =
379                                 to_service_driver(aerdev->device.driver);
380                 } else {
381                         dev_printk(KERN_DEBUG, &dev->dev, "no link-reset "
382                                    "support\n");
383                         return PCI_ERS_RESULT_DISCONNECT;
384                 }
385         }
386
387         status = data.aer_driver->reset_link(udev);
388         if (status != PCI_ERS_RESULT_RECOVERED) {
389                 dev_printk(KERN_DEBUG, &dev->dev, "link reset at upstream "
390                            "device %s failed\n", pci_name(udev));
391                 return PCI_ERS_RESULT_DISCONNECT;
392         }
393
394         return status;
395 }
396
397 /**
398  * do_recovery - handle nonfatal/fatal error recovery process
399  * @aerdev: pointer to a pcie_device data structure of root port
400  * @dev: pointer to a pci_dev data structure of agent detecting an error
401  * @severity: error severity type
402  *
403  * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast
404  * error detected message to all downstream drivers within a hierarchy in
405  * question and return the returned code.
406  */
407 static pci_ers_result_t do_recovery(struct pcie_device *aerdev,
408                 struct pci_dev *dev,
409                 int severity)
410 {
411         pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED;
412         enum pci_channel_state state;
413
414         if (severity == AER_FATAL)
415                 state = pci_channel_io_frozen;
416         else
417                 state = pci_channel_io_normal;
418
419         status = broadcast_error_message(dev,
420                         state,
421                         "error_detected",
422                         report_error_detected);
423
424         if (severity == AER_FATAL) {
425                 result = reset_link(aerdev, dev);
426                 if (result != PCI_ERS_RESULT_RECOVERED) {
427                         /* TODO: Should panic here? */
428                         return result;
429                 }
430         }
431
432         if (status == PCI_ERS_RESULT_CAN_RECOVER)
433                 status = broadcast_error_message(dev,
434                                 state,
435                                 "mmio_enabled",
436                                 report_mmio_enabled);
437
438         if (status == PCI_ERS_RESULT_NEED_RESET) {
439                 /*
440                  * TODO: Should call platform-specific
441                  * functions to reset slot before calling
442                  * drivers' slot_reset callbacks?
443                  */
444                 status = broadcast_error_message(dev,
445                                 state,
446                                 "slot_reset",
447                                 report_slot_reset);
448         }
449
450         if (status == PCI_ERS_RESULT_RECOVERED)
451                 broadcast_error_message(dev,
452                                 state,
453                                 "resume",
454                                 report_resume);
455
456         return status;
457 }
458
459 /**
460  * handle_error_source - handle logging error into an event log
461  * @aerdev: pointer to pcie_device data structure of the root port
462  * @dev: pointer to pci_dev data structure of error source device
463  * @info: comprehensive error information
464  *
465  * Invoked when an error being detected by Root Port.
466  */
467 static void handle_error_source(struct pcie_device * aerdev,
468         struct pci_dev *dev,
469         struct aer_err_info info)
470 {
471         pci_ers_result_t status = 0;
472         int pos;
473
474         if (info.severity == AER_CORRECTABLE) {
475                 /*
476                  * Correctable error does not need software intevention.
477                  * No need to go through error recovery process.
478                  */
479                 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
480                 if (pos)
481                         pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
482                                         info.status);
483         } else {
484                 status = do_recovery(aerdev, dev, info.severity);
485                 if (status == PCI_ERS_RESULT_RECOVERED) {
486                         dev_printk(KERN_DEBUG, &dev->dev, "AER driver "
487                                    "successfully recovered\n");
488                 } else {
489                         /* TODO: Should kernel panic here? */
490                         dev_printk(KERN_DEBUG, &dev->dev, "AER driver didn't "
491                                    "recover\n");
492                 }
493         }
494 }
495
496 /**
497  * aer_enable_rootport - enable Root Port's interrupts when receiving messages
498  * @rpc: pointer to a Root Port data structure
499  *
500  * Invoked when PCIE bus loads AER service driver.
501  */
502 void aer_enable_rootport(struct aer_rpc *rpc)
503 {
504         struct pci_dev *pdev = rpc->rpd->port;
505         int pos, aer_pos;
506         u16 reg16;
507         u32 reg32;
508
509         pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
510         /* Clear PCIE Capability's Device Status */
511         pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16);
512         pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16);
513
514         /* Disable system error generation in response to error messages */
515         pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, &reg16);
516         reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK);
517         pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16);
518
519         aer_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
520         /* Clear error status */
521         pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
522         pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
523         pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);
524         pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
525         pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
526         pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
527
528         /* Enable Root Port device reporting error itself */
529         pci_read_config_word(pdev, pos+PCI_EXP_DEVCTL, &reg16);
530         reg16 = reg16 |
531                 PCI_EXP_DEVCTL_CERE |
532                 PCI_EXP_DEVCTL_NFERE |
533                 PCI_EXP_DEVCTL_FERE |
534                 PCI_EXP_DEVCTL_URRE;
535         pci_write_config_word(pdev, pos+PCI_EXP_DEVCTL,
536                 reg16);
537
538         /* Enable Root Port's interrupt in response to error messages */
539         pci_write_config_dword(pdev,
540                 aer_pos + PCI_ERR_ROOT_COMMAND,
541                 ROOT_PORT_INTR_ON_MESG_MASK);
542 }
543
544 /**
545  * disable_root_aer - disable Root Port's interrupts when receiving messages
546  * @rpc: pointer to a Root Port data structure
547  *
548  * Invoked when PCIE bus unloads AER service driver.
549  */
550 static void disable_root_aer(struct aer_rpc *rpc)
551 {
552         struct pci_dev *pdev = rpc->rpd->port;
553         u32 reg32;
554         int pos;
555
556         pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
557         /* Disable Root's interrupt in response to error messages */
558         pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0);
559
560         /* Clear Root's error status reg */
561         pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);
562         pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
563 }
564
565 /**
566  * get_e_source - retrieve an error source
567  * @rpc: pointer to the root port which holds an error
568  *
569  * Invoked by DPC handler to consume an error.
570  */
571 static struct aer_err_source* get_e_source(struct aer_rpc *rpc)
572 {
573         struct aer_err_source *e_source;
574         unsigned long flags;
575
576         /* Lock access to Root error producer/consumer index */
577         spin_lock_irqsave(&rpc->e_lock, flags);
578         if (rpc->prod_idx == rpc->cons_idx) {
579                 spin_unlock_irqrestore(&rpc->e_lock, flags);
580                 return NULL;
581         }
582         e_source = &rpc->e_sources[rpc->cons_idx];
583         rpc->cons_idx++;
584         if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)
585                 rpc->cons_idx = 0;
586         spin_unlock_irqrestore(&rpc->e_lock, flags);
587
588         return e_source;
589 }
590
591 static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
592 {
593         int pos;
594
595         pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
596
597         /* The device might not support AER */
598         if (!pos)
599                 return AER_SUCCESS;
600
601         if (info->severity == AER_CORRECTABLE) {
602                 pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS,
603                         &info->status);
604                 if (!(info->status & ERR_CORRECTABLE_ERROR_MASK))
605                         return AER_UNSUCCESS;
606         } else if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE ||
607                 info->severity == AER_NONFATAL) {
608
609                 /* Link is still healthy for IO reads */
610                 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
611                         &info->status);
612                 if (!(info->status & ERR_UNCORRECTABLE_ERROR_MASK))
613                         return AER_UNSUCCESS;
614
615                 if (info->status & AER_LOG_TLP_MASKS) {
616                         info->flags |= AER_TLP_HEADER_VALID_FLAG;
617                         pci_read_config_dword(dev,
618                                 pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0);
619                         pci_read_config_dword(dev,
620                                 pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1);
621                         pci_read_config_dword(dev,
622                                 pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2);
623                         pci_read_config_dword(dev,
624                                 pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3);
625                 }
626         }
627
628         return AER_SUCCESS;
629 }
630
631 /**
632  * aer_isr_one_error - consume an error detected by root port
633  * @p_device: pointer to error root port service device
634  * @e_src: pointer to an error source
635  */
636 static void aer_isr_one_error(struct pcie_device *p_device,
637                 struct aer_err_source *e_src)
638 {
639         struct device *s_device;
640         struct aer_err_info e_info = {0, 0, 0,};
641         int i;
642         u16 id;
643
644         /*
645          * There is a possibility that both correctable error and
646          * uncorrectable error being logged. Report correctable error first.
647          */
648         for (i = 1; i & ROOT_ERR_STATUS_MASKS ; i <<= 2) {
649                 if (i > 4)
650                         break;
651                 if (!(e_src->status & i))
652                         continue;
653
654                 /* Init comprehensive error information */
655                 if (i & PCI_ERR_ROOT_COR_RCV) {
656                         id = ERR_COR_ID(e_src->id);
657                         e_info.severity = AER_CORRECTABLE;
658                 } else {
659                         id = ERR_UNCOR_ID(e_src->id);
660                         e_info.severity = ((e_src->status >> 6) & 1);
661                 }
662                 if (e_src->status &
663                         (PCI_ERR_ROOT_MULTI_COR_RCV |
664                          PCI_ERR_ROOT_MULTI_UNCOR_RCV))
665                         e_info.flags |= AER_MULTI_ERROR_VALID_FLAG;
666                 if (!(s_device = find_source_device(p_device->port, id))) {
667                         printk(KERN_DEBUG "%s->can't find device of ID%04x\n",
668                                 __func__, id);
669                         continue;
670                 }
671                 if (get_device_error_info(to_pci_dev(s_device), &e_info) ==
672                                 AER_SUCCESS) {
673                         aer_print_error(to_pci_dev(s_device), &e_info);
674                         handle_error_source(p_device,
675                                 to_pci_dev(s_device),
676                                 e_info);
677                 }
678         }
679 }
680
681 /**
682  * aer_isr - consume errors detected by root port
683  * @work: definition of this work item
684  *
685  * Invoked, as DPC, when root port records new detected error
686  */
687 void aer_isr(struct work_struct *work)
688 {
689         struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler);
690         struct pcie_device *p_device = rpc->rpd;
691         struct aer_err_source *e_src;
692
693         mutex_lock(&rpc->rpc_mutex);
694         e_src = get_e_source(rpc);
695         while (e_src) {
696                 aer_isr_one_error(p_device, e_src);
697                 e_src = get_e_source(rpc);
698         }
699         mutex_unlock(&rpc->rpc_mutex);
700
701         wake_up(&rpc->wait_release);
702 }
703
704 /**
705  * aer_delete_rootport - disable root port aer and delete service data
706  * @rpc: pointer to a root port device being deleted
707  *
708  * Invoked when AER service unloaded on a specific Root Port
709  */
710 void aer_delete_rootport(struct aer_rpc *rpc)
711 {
712         /* Disable root port AER itself */
713         disable_root_aer(rpc);
714
715         kfree(rpc);
716 }
717
718 /**
719  * aer_init - provide AER initialization
720  * @dev: pointer to AER pcie device
721  *
722  * Invoked when AER service driver is loaded.
723  */
724 int aer_init(struct pcie_device *dev)
725 {
726         if (aer_osc_setup(dev) && !forceload)
727                 return -ENXIO;
728
729         return AER_SUCCESS;
730 }
731
732 EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);
733 EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
734 EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
735