aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/PCI/pcieaer-howto.txt15
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c23
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h1
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c78
4 files changed, 71 insertions, 46 deletions
diff --git a/Documentation/PCI/pcieaer-howto.txt b/Documentation/PCI/pcieaer-howto.txt
index 8c406a49679..26d3d945c3c 100644
--- a/Documentation/PCI/pcieaer-howto.txt
+++ b/Documentation/PCI/pcieaer-howto.txt
@@ -13,7 +13,7 @@ Reporting (AER) driver and provides information on how to use it, as
13well as how to enable the drivers of endpoint devices to conform with 13well as how to enable the drivers of endpoint devices to conform with
14PCI Express AER driver. 14PCI Express AER driver.
15 15
161.2 Copyright © Intel Corporation 2006. 161.2 Copyright (C) Intel Corporation 2006.
17 17
181.3 What is the PCI Express AER Driver? 181.3 What is the PCI Express AER Driver?
19 19
@@ -108,7 +108,7 @@ but the PCI Express link itself is fully functional. Fatal errors, on
108the other hand, cause the link to be unreliable. 108the other hand, cause the link to be unreliable.
109 109
110When AER is enabled, a PCI Express device will automatically send an 110When AER is enabled, a PCI Express device will automatically send an
111error message to the PCIE root port above it when the device captures 111error message to the PCIe root port above it when the device captures
112an error. The Root Port, upon receiving an error reporting message, 112an error. The Root Port, upon receiving an error reporting message,
113internally processes and logs the error message in its PCI Express 113internally processes and logs the error message in its PCI Express
114capability structure. Error information being logged includes storing 114capability structure. Error information being logged includes storing
@@ -194,8 +194,9 @@ to reset link, AER port service driver is required to provide the
194function to reset link. Firstly, kernel looks for if the upstream 194function to reset link. Firstly, kernel looks for if the upstream
195component has an aer driver. If it has, kernel uses the reset_link 195component has an aer driver. If it has, kernel uses the reset_link
196callback of the aer driver. If the upstream component has no aer driver 196callback of the aer driver. If the upstream component has no aer driver
197and the port is downstream port, we will use the aer driver of the 197and the port is downstream port, we will perform a hot reset as the
198root port who reports the AER error. As for upstream ports, 198default by setting the Secondary Bus Reset bit of the Bridge Control
199register associated with the downstream port. As for upstream ports,
199they should provide their own aer service drivers with reset_link 200they should provide their own aer service drivers with reset_link
200function. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER and 201function. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER and
201reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes 202reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes
@@ -249,11 +250,11 @@ cleanup uncorrectable status register. Pls. refer to section 3.3.
249 250
2504. Software error injection 2514. Software error injection
251 252
252Debugging PCIE AER error recovery code is quite difficult because it 253Debugging PCIe AER error recovery code is quite difficult because it
253is hard to trigger real hardware errors. Software based error 254is hard to trigger real hardware errors. Software based error
254injection can be used to fake various kinds of PCIE errors. 255injection can be used to fake various kinds of PCIe errors.
255 256
256First you should enable PCIE AER software error injection in kernel 257First you should enable PCIe AER software error injection in kernel
257configuration, that is, following item should be in your .config. 258configuration, that is, following item should be in your .config.
258 259
259CONFIG_PCIEAER_INJECT=y or CONFIG_PCIEAER_INJECT=m 260CONFIG_PCIEAER_INJECT=y or CONFIG_PCIEAER_INJECT=m
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index cbc7cc77b2c..a225d58c1ac 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -341,7 +341,6 @@ static int __devinit aer_probe(struct pcie_device *dev)
341 **/ 341 **/
342static pci_ers_result_t aer_root_reset(struct pci_dev *dev) 342static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
343{ 343{
344 u16 p2p_ctrl;
345 u32 reg32; 344 u32 reg32;
346 int pos; 345 int pos;
347 346
@@ -352,27 +351,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
352 reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; 351 reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
353 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); 352 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
354 353
355 /* Assert Secondary Bus Reset */ 354 aer_do_secondary_bus_reset(dev);
356 pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
357 p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
358 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
359
360 /*
361 * we should send hot reset message for 2ms to allow it time to
362 * propogate to all downstream ports
363 */
364 msleep(2);
365
366 /* De-assert Secondary Bus Reset */
367 p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
368 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
369
370 /*
371 * System software must wait for at least 100ms from the end
372 * of a reset of one or more device before it is permitted
373 * to issue Configuration Requests to those devices.
374 */
375 msleep(200);
376 dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n"); 355 dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
377 356
378 /* Clear Root Error Status */ 357 /* Clear Root Error Status */
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index d0f8291c5ca..7aaae2d2bd6 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -114,6 +114,7 @@ static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
114} 114}
115 115
116extern struct bus_type pcie_port_bus_type; 116extern struct bus_type pcie_port_bus_type;
117extern void aer_do_secondary_bus_reset(struct pci_dev *dev);
117extern int aer_init(struct pcie_device *dev); 118extern int aer_init(struct pcie_device *dev);
118extern void aer_isr(struct work_struct *work); 119extern void aer_isr(struct work_struct *work);
119extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); 120extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 8fb14aeb74d..ce42cac99dd 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -373,6 +373,53 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
373 return result_data.result; 373 return result_data.result;
374} 374}
375 375
376/**
377 * aer_do_secondary_bus_reset - perform secondary bus reset
378 * @dev: pointer to bridge's pci_dev data structure
379 *
380 * Invoked when performing link reset at Root Port or Downstream Port.
381 */
382void aer_do_secondary_bus_reset(struct pci_dev *dev)
383{
384 u16 p2p_ctrl;
385
386 /* Assert Secondary Bus Reset */
387 pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
388 p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
389 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
390
391 /*
392 * we should send hot reset message for 2ms to allow it time to
393 * propagate to all downstream ports
394 */
395 msleep(2);
396
397 /* De-assert Secondary Bus Reset */
398 p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
399 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
400
401 /*
402 * System software must wait for at least 100ms from the end
403 * of a reset of one or more device before it is permitted
404 * to issue Configuration Requests to those devices.
405 */
406 msleep(200);
407}
408
409/**
410 * default_downstream_reset_link - default reset function for Downstream Port
411 * @dev: pointer to downstream port's pci_dev data structure
412 *
413 * Invoked when performing link reset at Downstream Port w/ no aer driver.
414 */
415static pci_ers_result_t default_downstream_reset_link(struct pci_dev *dev)
416{
417 aer_do_secondary_bus_reset(dev);
418 dev_printk(KERN_DEBUG, &dev->dev,
419 "Downstream Port link has been reset\n");
420 return PCI_ERS_RESULT_RECOVERED;
421}
422
376static int find_aer_service_iter(struct device *device, void *data) 423static int find_aer_service_iter(struct device *device, void *data)
377{ 424{
378 struct pcie_port_service_driver *service_driver, **drv; 425 struct pcie_port_service_driver *service_driver, **drv;
@@ -406,31 +453,28 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev,
406 pci_ers_result_t status; 453 pci_ers_result_t status;
407 struct pcie_port_service_driver *driver; 454 struct pcie_port_service_driver *driver;
408 455
409 if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) 456 if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
457 /* Reset this port for all subordinates */
410 udev = dev; 458 udev = dev;
411 else 459 } else {
460 /* Reset the upstream component (likely downstream port) */
412 udev = dev->bus->self; 461 udev = dev->bus->self;
462 }
413 463
414 /* Use the aer driver of the component firstly */ 464 /* Use the aer driver of the component firstly */
415 driver = find_aer_service(udev); 465 driver = find_aer_service(udev);
416 466
417 /* 467 if (driver && driver->reset_link) {
418 * If it hasn't the driver and is downstream port, use the root port's 468 status = driver->reset_link(udev);
419 */ 469 } else if (udev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) {
420 if (!driver || !driver->reset_link) { 470 status = default_downstream_reset_link(udev);
421 if (udev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM && 471 } else {
422 aerdev->device.driver && 472 dev_printk(KERN_DEBUG, &dev->dev,
423 to_service_driver(aerdev->device.driver)->reset_link) { 473 "no link-reset support at upstream device %s\n",
424 driver = to_service_driver(aerdev->device.driver); 474 pci_name(udev));
425 } else { 475 return PCI_ERS_RESULT_DISCONNECT;
426 dev_printk(KERN_DEBUG, &dev->dev,
427 "no link-reset support at upstream device %s\n",
428 pci_name(udev));
429 return PCI_ERS_RESULT_DISCONNECT;
430 }
431 } 476 }
432 477
433 status = driver->reset_link(udev);
434 if (status != PCI_ERS_RESULT_RECOVERED) { 478 if (status != PCI_ERS_RESULT_RECOVERED) {
435 dev_printk(KERN_DEBUG, &dev->dev, 479 dev_printk(KERN_DEBUG, &dev->dev,
436 "link reset at upstream device %s failed\n", 480 "link reset at upstream device %s failed\n",