aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pcie/aer
diff options
context:
space:
mode:
authorHidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>2010-04-15 00:21:27 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-05-11 15:01:38 -0400
commit89713422a768458a0d375f0c2f3586cd5ccde6a1 (patch)
treec446440123602cdb5320617ac7a8c2dbf514ff41 /drivers/pci/pcie/aer
parent517cae3829ae8cc3033c24f60e64eb251b2f0d14 (diff)
PCI: aerdrv: introduce default_downstream_reset_link
I noticed that when I inject a fatal error to an endpoint via aer-inject, aer_root_reset() is called as reset_link for a downstream port at upstream of the endpoint: pcieport 0000:00:06.0: AER: Uncorrected (Fatal) error received: id=5401 : pcieport 0000:52:02.0: Root Port link has been reset It externally appears to be working, but internally issues some accesses to PCI_ERR_ROOT_COMMAND/STATUS registers that is for root port so not available on downstream port. This patch introduces default_downstream_reset_link that is a version of aer_root_reset() with no accesses to root port's register. It is used for downstream ports that has no reset_link function its specific. This patch also updates related description in pcieaer-howto.txt. Some minor fixes are included. Signed-off-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com> Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pcie/aer')
-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
3 files changed, 63 insertions, 39 deletions
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index cbc7cc77b2c3..a225d58c1ac8 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 d0f8291c5ca0..7aaae2d2bd67 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 8fb14aeb74dd..ce42cac99dd3 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",