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