]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/pci/pcie/aer/aerdrv_core.c
PCI: PCIe: Ask BIOS for control of all native services at once
[net-next-2.6.git] / drivers / pci / pcie / aer / aerdrv_core.c
CommitLineData
6c2b374d
ZY
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>
6c2b374d 25#include <linux/delay.h>
5a0e3ad6 26#include <linux/slab.h>
6c2b374d
ZY
27#include "aerdrv.h"
28
29static int forceload;
28eb27cf 30static int nosourceid;
6c2b374d 31module_param(forceload, bool, 0);
28eb27cf 32module_param(nosourceid, bool, 0);
6c2b374d 33
6c2b374d
ZY
34int pci_enable_pcie_error_reporting(struct pci_dev *dev)
35{
36 u16 reg16 = 0;
37 int pos;
38
affb72c3 39 if (pcie_aer_get_firmware_first(dev))
05843961
MD
40 return -EIO;
41
270c66be 42 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
6c2b374d
ZY
43 if (!pos)
44 return -EIO;
45
39a53062 46 pos = pci_pcie_cap(dev);
0927678f
JB
47 if (!pos)
48 return -EIO;
49
caa5afbd
HS
50 pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
51 reg16 |= (PCI_EXP_DEVCTL_CERE |
6c2b374d
ZY
52 PCI_EXP_DEVCTL_NFERE |
53 PCI_EXP_DEVCTL_FERE |
caa5afbd
HS
54 PCI_EXP_DEVCTL_URRE);
55 pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16);
c9a91883 56
6c2b374d
ZY
57 return 0;
58}
c9a91883 59EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);
6c2b374d
ZY
60
61int pci_disable_pcie_error_reporting(struct pci_dev *dev)
62{
63 u16 reg16 = 0;
64 int pos;
65
affb72c3 66 if (pcie_aer_get_firmware_first(dev))
05843961
MD
67 return -EIO;
68
39a53062 69 pos = pci_pcie_cap(dev);
6c2b374d
ZY
70 if (!pos)
71 return -EIO;
72
caa5afbd
HS
73 pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
74 reg16 &= ~(PCI_EXP_DEVCTL_CERE |
75 PCI_EXP_DEVCTL_NFERE |
76 PCI_EXP_DEVCTL_FERE |
77 PCI_EXP_DEVCTL_URRE);
78 pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16);
c9a91883 79
6c2b374d
ZY
80 return 0;
81}
c9a91883 82EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
6c2b374d
ZY
83
84int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
85{
86 int pos;
6cdfd995 87 u32 status;
6c2b374d 88
0927678f 89 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
6c2b374d
ZY
90 if (!pos)
91 return -EIO;
92
93 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
6cdfd995
AP
94 if (status)
95 pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
6c2b374d
ZY
96
97 return 0;
98}
c9a91883 99EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
6c2b374d 100
4a0c096e
HS
101/**
102 * add_error_device - list device to be handled
103 * @e_info: pointer to error info
104 * @dev: pointer to pci_dev to be added
105 */
3d5505c5
ZY
106static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev)
107{
108 if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) {
109 e_info->dev[e_info->error_dev_num] = dev;
110 e_info->error_dev_num++;
4a0c096e 111 return 0;
c9a91883 112 }
4a0c096e 113 return -ENOSPC;
3d5505c5
ZY
114}
115
28eb27cf
ZY
116#define PCI_BUS(x) (((x) >> 8) & 0xff)
117
c887275e
HS
118/**
119 * is_error_source - check whether the device is source of reported error
120 * @dev: pointer to pci_dev to be checked
121 * @e_info: pointer to reported error info
122 */
123static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
28eb27cf
ZY
124{
125 int pos;
c887275e 126 u32 status, mask;
28eb27cf 127 u16 reg16;
28eb27cf
ZY
128
129 /*
130 * When bus id is equal to 0, it might be a bad id
131 * reported by root port.
132 */
133 if (!nosourceid && (PCI_BUS(e_info->id) != 0)) {
bd17d474
HS
134 /* Device ID match? */
135 if (e_info->id == ((dev->bus->number << 8) | dev->devfn))
c887275e 136 return true;
3d5505c5 137
c887275e 138 /* Continue id comparing if there is no multiple error */
273024de 139 if (!e_info->multi_error_valid)
c887275e 140 return false;
28eb27cf
ZY
141 }
142
143 /*
3d5505c5
ZY
144 * When either
145 * 1) nosourceid==y;
146 * 2) bus id is equal to 0. Some ports might lose the bus
147 * id of error source id;
148 * 3) There are multiple errors and prior id comparing fails;
c887275e 149 * We check AER status registers to find possible reporter.
28eb27cf
ZY
150 */
151 if (atomic_read(&dev->enable_cnt) == 0)
c887275e 152 return false;
39a53062 153 pos = pci_pcie_cap(dev);
28eb27cf 154 if (!pos)
c887275e
HS
155 return false;
156
28eb27cf 157 /* Check if AER is enabled */
c887275e 158 pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
28eb27cf
ZY
159 if (!(reg16 & (
160 PCI_EXP_DEVCTL_CERE |
161 PCI_EXP_DEVCTL_NFERE |
162 PCI_EXP_DEVCTL_FERE |
163 PCI_EXP_DEVCTL_URRE)))
c887275e 164 return false;
28eb27cf
ZY
165 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
166 if (!pos)
c887275e 167 return false;
28eb27cf 168
c887275e 169 /* Check if error is recorded */
28eb27cf 170 if (e_info->severity == AER_CORRECTABLE) {
0d90c3ac
HS
171 pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status);
172 pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &mask);
28eb27cf 173 } else {
0d90c3ac
HS
174 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
175 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &mask);
6c2b374d 176 }
c887275e
HS
177 if (status & ~mask)
178 return true;
6c2b374d 179
c887275e
HS
180 return false;
181}
3d5505c5 182
c887275e
HS
183static int find_device_iter(struct pci_dev *dev, void *data)
184{
185 struct aer_err_info *e_info = (struct aer_err_info *)data;
186
187 if (is_error_source(dev, e_info)) {
4a0c096e
HS
188 /* List this device */
189 if (add_error_device(e_info, dev)) {
190 /* We cannot handle more... Stop iteration */
191 /* TODO: Should print error message here? */
192 return 1;
193 }
c887275e
HS
194
195 /* If there is only a single error, stop iteration */
196 if (!e_info->multi_error_valid)
197 return 1;
198 }
199 return 0;
6c2b374d
ZY
200}
201
202/**
203 * find_source_device - search through device hierarchy for source device
d885c6b7 204 * @parent: pointer to Root Port pci_dev data structure
98ca3964 205 * @e_info: including detailed error information such like id
6c2b374d 206 *
98ca3964
HS
207 * Return true if found.
208 *
209 * Invoked by DPC when error is detected at the Root Port.
7c4ec94f
HS
210 * Caller of this function must set id, severity, and multi_error_valid of
211 * struct aer_err_info pointed by @e_info properly. This function must fill
212 * e_info->error_dev_num and e_info->dev[], based on the given information.
d885c6b7 213 */
98ca3964 214static bool find_source_device(struct pci_dev *parent,
28eb27cf 215 struct aer_err_info *e_info)
6c2b374d
ZY
216{
217 struct pci_dev *dev = parent;
28eb27cf 218 int result;
6c2b374d 219
7c4ec94f
HS
220 /* Must reset in this function */
221 e_info->error_dev_num = 0;
222
6c2b374d 223 /* Is Root Port an agent that sends error message? */
28eb27cf
ZY
224 result = find_device_iter(dev, e_info);
225 if (result)
98ca3964 226 return true;
6c2b374d 227
28eb27cf 228 pci_walk_bus(parent->subordinate, find_device_iter, e_info);
98ca3964
HS
229
230 if (!e_info->error_dev_num) {
231 dev_printk(KERN_DEBUG, &parent->dev,
232 "can't find device of ID%04x\n",
233 e_info->id);
234 return false;
235 }
236 return true;
6c2b374d
ZY
237}
238
70298c6e 239static int report_error_detected(struct pci_dev *dev, void *data)
6c2b374d
ZY
240{
241 pci_ers_result_t vote;
242 struct pci_error_handlers *err_handler;
243 struct aer_broadcast_data *result_data;
244 result_data = (struct aer_broadcast_data *) data;
245
246 dev->error_state = result_data->state;
247
248 if (!dev->driver ||
249 !dev->driver->err_handler ||
250 !dev->driver->err_handler->error_detected) {
251 if (result_data->state == pci_channel_io_frozen &&
252 !(dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) {
253 /*
254 * In case of fatal recovery, if one of down-
255 * stream device has no driver. We might be
256 * unable to recover because a later insmod
257 * of a driver for this device is unaware of
258 * its hw state.
259 */
531f254e
BH
260 dev_printk(KERN_DEBUG, &dev->dev, "device has %s\n",
261 dev->driver ?
262 "no AER-aware driver" : "no driver");
6c2b374d 263 }
70298c6e 264 return 0;
6c2b374d
ZY
265 }
266
267 err_handler = dev->driver->err_handler;
268 vote = err_handler->error_detected(dev, result_data->state);
269 result_data->result = merge_result(result_data->result, vote);
70298c6e 270 return 0;
6c2b374d
ZY
271}
272
70298c6e 273static int report_mmio_enabled(struct pci_dev *dev, void *data)
6c2b374d
ZY
274{
275 pci_ers_result_t vote;
276 struct pci_error_handlers *err_handler;
277 struct aer_broadcast_data *result_data;
278 result_data = (struct aer_broadcast_data *) data;
279
280 if (!dev->driver ||
281 !dev->driver->err_handler ||
282 !dev->driver->err_handler->mmio_enabled)
70298c6e 283 return 0;
6c2b374d
ZY
284
285 err_handler = dev->driver->err_handler;
286 vote = err_handler->mmio_enabled(dev);
287 result_data->result = merge_result(result_data->result, vote);
70298c6e 288 return 0;
6c2b374d
ZY
289}
290
70298c6e 291static int report_slot_reset(struct pci_dev *dev, void *data)
6c2b374d
ZY
292{
293 pci_ers_result_t vote;
294 struct pci_error_handlers *err_handler;
295 struct aer_broadcast_data *result_data;
296 result_data = (struct aer_broadcast_data *) data;
297
298 if (!dev->driver ||
299 !dev->driver->err_handler ||
300 !dev->driver->err_handler->slot_reset)
70298c6e 301 return 0;
6c2b374d
ZY
302
303 err_handler = dev->driver->err_handler;
304 vote = err_handler->slot_reset(dev);
305 result_data->result = merge_result(result_data->result, vote);
70298c6e 306 return 0;
6c2b374d
ZY
307}
308
70298c6e 309static int report_resume(struct pci_dev *dev, void *data)
6c2b374d
ZY
310{
311 struct pci_error_handlers *err_handler;
312
313 dev->error_state = pci_channel_io_normal;
314
315 if (!dev->driver ||
316 !dev->driver->err_handler ||
b0b801dd 317 !dev->driver->err_handler->resume)
70298c6e 318 return 0;
6c2b374d
ZY
319
320 err_handler = dev->driver->err_handler;
321 err_handler->resume(dev);
70298c6e 322 return 0;
6c2b374d
ZY
323}
324
325/**
326 * broadcast_error_message - handle message broadcast to downstream drivers
d885c6b7 327 * @dev: pointer to from where in a hierarchy message is broadcasted down
6c2b374d 328 * @state: error state
d885c6b7
RD
329 * @error_mesg: message to print
330 * @cb: callback to be broadcasted
6c2b374d
ZY
331 *
332 * Invoked during error recovery process. Once being invoked, the content
333 * of error severity will be broadcasted to all downstream drivers in a
334 * hierarchy in question.
d885c6b7 335 */
6c2b374d
ZY
336static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
337 enum pci_channel_state state,
338 char *error_mesg,
70298c6e 339 int (*cb)(struct pci_dev *, void *))
6c2b374d
ZY
340{
341 struct aer_broadcast_data result_data;
342
531f254e 343 dev_printk(KERN_DEBUG, &dev->dev, "broadcast %s message\n", error_mesg);
6c2b374d
ZY
344 result_data.state = state;
345 if (cb == report_error_detected)
346 result_data.result = PCI_ERS_RESULT_CAN_RECOVER;
347 else
348 result_data.result = PCI_ERS_RESULT_RECOVERED;
349
350 if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
351 /*
352 * If the error is reported by a bridge, we think this error
353 * is related to the downstream link of the bridge, so we
354 * do error recovery on all subordinates of the bridge instead
355 * of the bridge and clear the error status of the bridge.
356 */
357 if (cb == report_error_detected)
358 dev->error_state = state;
359 pci_walk_bus(dev->subordinate, cb, &result_data);
360 if (cb == report_resume) {
361 pci_cleanup_aer_uncorrect_error_status(dev);
362 dev->error_state = pci_channel_io_normal;
363 }
c9a91883 364 } else {
6c2b374d
ZY
365 /*
366 * If the error is reported by an end point, we think this
367 * error is related to the upstream link of the end point.
368 */
369 pci_walk_bus(dev->bus, cb, &result_data);
370 }
371
372 return result_data.result;
373}
374
89713422
HS
375/**
376 * aer_do_secondary_bus_reset - perform secondary bus reset
377 * @dev: pointer to bridge's pci_dev data structure
378 *
379 * Invoked when performing link reset at Root Port or Downstream Port.
380 */
381void aer_do_secondary_bus_reset(struct pci_dev *dev)
382{
383 u16 p2p_ctrl;
384
385 /* Assert Secondary Bus Reset */
386 pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
387 p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
388 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
389
390 /*
391 * we should send hot reset message for 2ms to allow it time to
392 * propagate to all downstream ports
393 */
394 msleep(2);
395
396 /* De-assert Secondary Bus Reset */
397 p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
398 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
399
400 /*
401 * System software must wait for at least 100ms from the end
402 * of a reset of one or more device before it is permitted
403 * to issue Configuration Requests to those devices.
404 */
405 msleep(200);
406}
407
408/**
409 * default_downstream_reset_link - default reset function for Downstream Port
410 * @dev: pointer to downstream port's pci_dev data structure
411 *
412 * Invoked when performing link reset at Downstream Port w/ no aer driver.
413 */
414static pci_ers_result_t default_downstream_reset_link(struct pci_dev *dev)
415{
416 aer_do_secondary_bus_reset(dev);
417 dev_printk(KERN_DEBUG, &dev->dev,
418 "Downstream Port link has been reset\n");
419 return PCI_ERS_RESULT_RECOVERED;
420}
421
6c2b374d
ZY
422static int find_aer_service_iter(struct device *device, void *data)
423{
517cae38 424 struct pcie_port_service_driver *service_driver, **drv;
6c2b374d 425
517cae38 426 drv = (struct pcie_port_service_driver **) data;
6c2b374d 427
4f7ccf6a
HS
428 if (device->bus == &pcie_port_bus_type && device->driver) {
429 service_driver = to_service_driver(device->driver);
430 if (service_driver->service == PCIE_PORT_SERVICE_AER) {
517cae38 431 *drv = service_driver;
4f7ccf6a 432 return 1;
6c2b374d
ZY
433 }
434 }
435
436 return 0;
437}
438
517cae38 439static struct pcie_port_service_driver *find_aer_service(struct pci_dev *dev)
6c2b374d 440{
517cae38
HS
441 struct pcie_port_service_driver *drv = NULL;
442
443 device_for_each_child(&dev->dev, &drv, find_aer_service_iter);
444
445 return drv;
6c2b374d
ZY
446}
447
448static pci_ers_result_t reset_link(struct pcie_device *aerdev,
449 struct pci_dev *dev)
450{
451 struct pci_dev *udev;
452 pci_ers_result_t status;
517cae38 453 struct pcie_port_service_driver *driver;
6c2b374d 454
89713422
HS
455 if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
456 /* Reset this port for all subordinates */
6c2b374d 457 udev = dev;
89713422
HS
458 } else {
459 /* Reset the upstream component (likely downstream port) */
c9a91883 460 udev = dev->bus->self;
89713422 461 }
6c2b374d 462
517cae38
HS
463 /* Use the aer driver of the component firstly */
464 driver = find_aer_service(udev);
6c2b374d 465
89713422
HS
466 if (driver && driver->reset_link) {
467 status = driver->reset_link(udev);
468 } else if (udev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) {
469 status = default_downstream_reset_link(udev);
470 } else {
471 dev_printk(KERN_DEBUG, &dev->dev,
472 "no link-reset support at upstream device %s\n",
473 pci_name(udev));
474 return PCI_ERS_RESULT_DISCONNECT;
6c2b374d
ZY
475 }
476
6c2b374d 477 if (status != PCI_ERS_RESULT_RECOVERED) {
4f7ccf6a
HS
478 dev_printk(KERN_DEBUG, &dev->dev,
479 "link reset at upstream device %s failed\n",
480 pci_name(udev));
6c2b374d
ZY
481 return PCI_ERS_RESULT_DISCONNECT;
482 }
483
484 return status;
485}
486
487/**
488 * do_recovery - handle nonfatal/fatal error recovery process
489 * @aerdev: pointer to a pcie_device data structure of root port
490 * @dev: pointer to a pci_dev data structure of agent detecting an error
491 * @severity: error severity type
492 *
493 * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast
494 * error detected message to all downstream drivers within a hierarchy in
495 * question and return the returned code.
d885c6b7 496 */
17e21854 497static void do_recovery(struct pcie_device *aerdev, struct pci_dev *dev,
6c2b374d
ZY
498 int severity)
499{
500 pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED;
501 enum pci_channel_state state;
502
503 if (severity == AER_FATAL)
504 state = pci_channel_io_frozen;
505 else
506 state = pci_channel_io_normal;
507
508 status = broadcast_error_message(dev,
509 state,
510 "error_detected",
511 report_error_detected);
512
513 if (severity == AER_FATAL) {
514 result = reset_link(aerdev, dev);
17e21854
HS
515 if (result != PCI_ERS_RESULT_RECOVERED)
516 goto failed;
6c2b374d
ZY
517 }
518
519 if (status == PCI_ERS_RESULT_CAN_RECOVER)
520 status = broadcast_error_message(dev,
521 state,
522 "mmio_enabled",
523 report_mmio_enabled);
524
525 if (status == PCI_ERS_RESULT_NEED_RESET) {
526 /*
527 * TODO: Should call platform-specific
528 * functions to reset slot before calling
529 * drivers' slot_reset callbacks?
530 */
531 status = broadcast_error_message(dev,
532 state,
533 "slot_reset",
534 report_slot_reset);
535 }
536
17e21854
HS
537 if (status != PCI_ERS_RESULT_RECOVERED)
538 goto failed;
539
540 broadcast_error_message(dev,
6c2b374d
ZY
541 state,
542 "resume",
543 report_resume);
544
17e21854
HS
545 dev_printk(KERN_DEBUG, &dev->dev,
546 "AER driver successfully recovered\n");
547 return;
548
549failed:
550 /* TODO: Should kernel panic here? */
551 dev_printk(KERN_DEBUG, &dev->dev,
552 "AER driver didn't recover\n");
6c2b374d
ZY
553}
554
555/**
556 * handle_error_source - handle logging error into an event log
557 * @aerdev: pointer to pcie_device data structure of the root port
558 * @dev: pointer to pci_dev data structure of error source device
559 * @info: comprehensive error information
560 *
561 * Invoked when an error being detected by Root Port.
d885c6b7 562 */
c9a91883 563static void handle_error_source(struct pcie_device *aerdev,
6c2b374d 564 struct pci_dev *dev,
28eb27cf 565 struct aer_err_info *info)
6c2b374d 566{
6c2b374d
ZY
567 int pos;
568
28eb27cf 569 if (info->severity == AER_CORRECTABLE) {
6c2b374d
ZY
570 /*
571 * Correctable error does not need software intevention.
572 * No need to go through error recovery process.
573 */
0927678f 574 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
6c2b374d
ZY
575 if (pos)
576 pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
28eb27cf 577 info->status);
17e21854
HS
578 } else
579 do_recovery(aerdev, dev, info->severity);
6c2b374d
ZY
580}
581
b1c089b7
HS
582/**
583 * get_device_error_info - read error status from dev and store it to info
584 * @dev: pointer to the device expected to have a error record
585 * @info: pointer to structure to store the error record
586 *
587 * Return 1 on success, 0 on error.
7c4ec94f
HS
588 *
589 * Note that @info is reused among all error devices. Clear fields properly.
b1c089b7 590 */
6c2b374d
ZY
591static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
592{
e7a0d92b 593 int pos, temp;
6c2b374d 594
7c4ec94f 595 /* Must reset in this function */
1b4ffcf8 596 info->status = 0;
273024de 597 info->tlp_header_valid = 0;
1b4ffcf8 598
0927678f 599 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
6c2b374d
ZY
600
601 /* The device might not support AER */
602 if (!pos)
b1c089b7 603 return 1;
6c2b374d
ZY
604
605 if (info->severity == AER_CORRECTABLE) {
606 pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS,
607 &info->status);
0d90c3ac
HS
608 pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK,
609 &info->mask);
610 if (!(info->status & ~info->mask))
b1c089b7 611 return 0;
6c2b374d
ZY
612 } else if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE ||
613 info->severity == AER_NONFATAL) {
614
615 /* Link is still healthy for IO reads */
616 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
617 &info->status);
0d90c3ac
HS
618 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK,
619 &info->mask);
620 if (!(info->status & ~info->mask))
b1c089b7 621 return 0;
6c2b374d 622
e7a0d92b
HS
623 /* Get First Error Pointer */
624 pci_read_config_dword(dev, pos + PCI_ERR_CAP, &temp);
273024de 625 info->first_error = PCI_ERR_CAP_FEP(temp);
e7a0d92b 626
6c2b374d 627 if (info->status & AER_LOG_TLP_MASKS) {
273024de 628 info->tlp_header_valid = 1;
6c2b374d
ZY
629 pci_read_config_dword(dev,
630 pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0);
631 pci_read_config_dword(dev,
632 pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1);
633 pci_read_config_dword(dev,
634 pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2);
635 pci_read_config_dword(dev,
636 pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3);
637 }
638 }
639
b1c089b7 640 return 1;
6c2b374d
ZY
641}
642
3d5505c5
ZY
643static inline void aer_process_err_devices(struct pcie_device *p_device,
644 struct aer_err_info *e_info)
645{
646 int i;
647
b1c089b7 648 /* Report all before handle them, not to lost records by reset etc. */
3d5505c5 649 for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) {
b1c089b7 650 if (get_device_error_info(e_info->dev[i], e_info))
3d5505c5 651 aer_print_error(e_info->dev[i], e_info);
b1c089b7
HS
652 }
653 for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) {
654 if (get_device_error_info(e_info->dev[i], e_info))
655 handle_error_source(p_device, e_info->dev[i], e_info);
3d5505c5
ZY
656 }
657}
658
6c2b374d
ZY
659/**
660 * aer_isr_one_error - consume an error detected by root port
661 * @p_device: pointer to error root port service device
662 * @e_src: pointer to an error source
d885c6b7 663 */
6c2b374d
ZY
664static void aer_isr_one_error(struct pcie_device *p_device,
665 struct aer_err_source *e_src)
666{
28eb27cf 667 struct aer_err_info *e_info;
28eb27cf
ZY
668
669 /* struct aer_err_info might be big, so we allocate it with slab */
670 e_info = kmalloc(sizeof(struct aer_err_info), GFP_KERNEL);
7c4ec94f 671 if (!e_info) {
28eb27cf
ZY
672 dev_printk(KERN_DEBUG, &p_device->port->dev,
673 "Can't allocate mem when processing AER errors\n");
674 return;
675 }
6c2b374d
ZY
676
677 /*
678 * There is a possibility that both correctable error and
679 * uncorrectable error being logged. Report correctable error first.
680 */
7c4ec94f
HS
681 if (e_src->status & PCI_ERR_ROOT_COR_RCV) {
682 e_info->id = ERR_COR_ID(e_src->id);
683 e_info->severity = AER_CORRECTABLE;
684
685 if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV)
686 e_info->multi_error_valid = 1;
687 else
688 e_info->multi_error_valid = 0;
689
690 aer_print_port_info(p_device->port, e_info);
691
692 if (find_source_device(p_device->port, e_info))
693 aer_process_err_devices(p_device, e_info);
694 }
695
696 if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) {
697 e_info->id = ERR_UNCOR_ID(e_src->id);
698
699 if (e_src->status & PCI_ERR_ROOT_FATAL_RCV)
700 e_info->severity = AER_FATAL;
701 else
702 e_info->severity = AER_NONFATAL;
703
704 if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV)
273024de 705 e_info->multi_error_valid = 1;
7c4ec94f
HS
706 else
707 e_info->multi_error_valid = 0;
28eb27cf 708
79e4b89b
HS
709 aer_print_port_info(p_device->port, e_info);
710
98ca3964
HS
711 if (find_source_device(p_device->port, e_info))
712 aer_process_err_devices(p_device, e_info);
6c2b374d 713 }
28eb27cf
ZY
714
715 kfree(e_info);
6c2b374d
ZY
716}
717
88da13bf
HS
718/**
719 * get_e_source - retrieve an error source
720 * @rpc: pointer to the root port which holds an error
721 * @e_src: pointer to store retrieved error source
722 *
723 * Return 1 if an error source is retrieved, otherwise 0.
724 *
725 * Invoked by DPC handler to consume an error.
726 */
727static int get_e_source(struct aer_rpc *rpc, struct aer_err_source *e_src)
728{
729 unsigned long flags;
88da13bf
HS
730
731 /* Lock access to Root error producer/consumer index */
732 spin_lock_irqsave(&rpc->e_lock, flags);
f6735590
LT
733 if (rpc->prod_idx == rpc->cons_idx) {
734 spin_unlock_irqrestore(&rpc->e_lock, flags);
735 return 0;
88da13bf 736 }
f6735590
LT
737
738 *e_src = rpc->e_sources[rpc->cons_idx];
739 rpc->cons_idx++;
740 if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)
741 rpc->cons_idx = 0;
88da13bf
HS
742 spin_unlock_irqrestore(&rpc->e_lock, flags);
743
f6735590 744 return 1;
88da13bf
HS
745}
746
6c2b374d
ZY
747/**
748 * aer_isr - consume errors detected by root port
65f27f38 749 * @work: definition of this work item
6c2b374d
ZY
750 *
751 * Invoked, as DPC, when root port records new detected error
d885c6b7 752 */
65f27f38 753void aer_isr(struct work_struct *work)
6c2b374d 754{
65f27f38
DH
755 struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler);
756 struct pcie_device *p_device = rpc->rpd;
88da13bf 757 struct aer_err_source e_src;
6c2b374d
ZY
758
759 mutex_lock(&rpc->rpc_mutex);
88da13bf
HS
760 while (get_e_source(rpc, &e_src))
761 aer_isr_one_error(p_device, &e_src);
6c2b374d
ZY
762 mutex_unlock(&rpc->rpc_mutex);
763
764 wake_up(&rpc->wait_release);
765}
766
6c2b374d
ZY
767/**
768 * aer_init - provide AER initialization
769 * @dev: pointer to AER pcie device
770 *
771 * Invoked when AER service driver is loaded.
d885c6b7 772 */
6c2b374d
ZY
773int aer_init(struct pcie_device *dev)
774{
05843961
MD
775 if (forceload) {
776 dev_printk(KERN_DEBUG, &dev->device,
777 "aerdrv forceload requested.\n");
affb72c3 778 pcie_aer_force_firmware_first(dev->port, 0);
05843961 779 }
28eb5f27 780 return 0;
6c2b374d 781}