diff options
author | Gavin Shan <shangw@linux.vnet.ibm.com> | 2012-09-07 18:44:17 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-09-09 19:35:42 -0400 |
commit | c270a24c59bd9a4ac7dbcbd964cbd14270b3a361 (patch) | |
tree | 1a1be911c6db25795a866ce60a9f43971ee68076 /arch/powerpc/platforms | |
parent | ff477966c626e440dd1737801ae4d52cf1f22bff (diff) |
powerpc/eeh: Do reset based on PE
The patch implements reset based on PE instead of eeh device. Also,
The functions used to retrieve the reset type, either hot or fundamental
reset, have been reworked for a little bit. More specificly, it's
implemented based the the eeh device traverse function.
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh.c | 91 |
1 files changed, 34 insertions, 57 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 45723618b1df..56a022b03651 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -455,17 +455,24 @@ int eeh_pci_enable(struct eeh_pe *pe, int function) | |||
455 | */ | 455 | */ |
456 | int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) | 456 | int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) |
457 | { | 457 | { |
458 | struct device_node *dn = pci_device_to_OF_node(dev); | 458 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); |
459 | struct eeh_pe *pe = edev->pe; | ||
460 | |||
461 | if (!pe) { | ||
462 | pr_err("%s: No PE found on PCI device %s\n", | ||
463 | __func__, pci_name(dev)); | ||
464 | return -EINVAL; | ||
465 | } | ||
459 | 466 | ||
460 | switch (state) { | 467 | switch (state) { |
461 | case pcie_deassert_reset: | 468 | case pcie_deassert_reset: |
462 | eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); | 469 | eeh_ops->reset(pe, EEH_RESET_DEACTIVATE); |
463 | break; | 470 | break; |
464 | case pcie_hot_reset: | 471 | case pcie_hot_reset: |
465 | eeh_ops->reset(dn, EEH_RESET_HOT); | 472 | eeh_ops->reset(pe, EEH_RESET_HOT); |
466 | break; | 473 | break; |
467 | case pcie_warm_reset: | 474 | case pcie_warm_reset: |
468 | eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); | 475 | eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); |
469 | break; | 476 | break; |
470 | default: | 477 | default: |
471 | return -EINVAL; | 478 | return -EINVAL; |
@@ -475,66 +482,37 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat | |||
475 | } | 482 | } |
476 | 483 | ||
477 | /** | 484 | /** |
478 | * __eeh_set_pe_freset - Check the required reset for child devices | 485 | * eeh_set_pe_freset - Check the required reset for the indicated device |
479 | * @parent: parent device | 486 | * @data: EEH device |
480 | * @freset: return value | 487 | * @flag: return value |
481 | * | ||
482 | * Each device might have its preferred reset type: fundamental or | ||
483 | * hot reset. The routine is used to collect the information from | ||
484 | * the child devices so that they could be reset accordingly. | ||
485 | */ | ||
486 | void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) | ||
487 | { | ||
488 | struct device_node *dn; | ||
489 | |||
490 | for_each_child_of_node(parent, dn) { | ||
491 | if (of_node_to_eeh_dev(dn)) { | ||
492 | struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; | ||
493 | |||
494 | if (dev && dev->driver) | ||
495 | *freset |= dev->needs_freset; | ||
496 | |||
497 | __eeh_set_pe_freset(dn, freset); | ||
498 | } | ||
499 | } | ||
500 | } | ||
501 | |||
502 | /** | ||
503 | * eeh_set_pe_freset - Check the required reset for the indicated device and its children | ||
504 | * @dn: parent device | ||
505 | * @freset: return value | ||
506 | * | 488 | * |
507 | * Each device might have its preferred reset type: fundamental or | 489 | * Each device might have its preferred reset type: fundamental or |
508 | * hot reset. The routine is used to collected the information for | 490 | * hot reset. The routine is used to collected the information for |
509 | * the indicated device and its children so that the bunch of the | 491 | * the indicated device and its children so that the bunch of the |
510 | * devices could be reset properly. | 492 | * devices could be reset properly. |
511 | */ | 493 | */ |
512 | void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) | 494 | static void *eeh_set_dev_freset(void *data, void *flag) |
513 | { | 495 | { |
514 | struct pci_dev *dev; | 496 | struct pci_dev *dev; |
515 | dn = eeh_find_device_pe(dn); | 497 | unsigned int *freset = (unsigned int *)flag; |
516 | 498 | struct eeh_dev *edev = (struct eeh_dev *)data; | |
517 | /* Back up one, since config addrs might be shared */ | ||
518 | if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) | ||
519 | dn = dn->parent; | ||
520 | 499 | ||
521 | dev = of_node_to_eeh_dev(dn)->pdev; | 500 | dev = eeh_dev_to_pci_dev(edev); |
522 | if (dev) | 501 | if (dev) |
523 | *freset |= dev->needs_freset; | 502 | *freset |= dev->needs_freset; |
524 | 503 | ||
525 | __eeh_set_pe_freset(dn, freset); | 504 | return NULL; |
526 | } | 505 | } |
527 | 506 | ||
528 | /** | 507 | /** |
529 | * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second | 508 | * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second |
530 | * @edev: pci device node to be reset. | 509 | * @pe: EEH PE |
531 | * | 510 | * |
532 | * Assert the PCI #RST line for 1/4 second. | 511 | * Assert the PCI #RST line for 1/4 second. |
533 | */ | 512 | */ |
534 | static void eeh_reset_pe_once(struct eeh_dev *edev) | 513 | static void eeh_reset_pe_once(struct eeh_pe *pe) |
535 | { | 514 | { |
536 | unsigned int freset = 0; | 515 | unsigned int freset = 0; |
537 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
538 | 516 | ||
539 | /* Determine type of EEH reset required for | 517 | /* Determine type of EEH reset required for |
540 | * Partitionable Endpoint, a hot-reset (1) | 518 | * Partitionable Endpoint, a hot-reset (1) |
@@ -542,12 +520,12 @@ static void eeh_reset_pe_once(struct eeh_dev *edev) | |||
542 | * A fundamental reset required by any device under | 520 | * A fundamental reset required by any device under |
543 | * Partitionable Endpoint trumps hot-reset. | 521 | * Partitionable Endpoint trumps hot-reset. |
544 | */ | 522 | */ |
545 | eeh_set_pe_freset(dn, &freset); | 523 | eeh_pe_dev_traverse(pe, eeh_set_dev_freset, &freset); |
546 | 524 | ||
547 | if (freset) | 525 | if (freset) |
548 | eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); | 526 | eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); |
549 | else | 527 | else |
550 | eeh_ops->reset(dn, EEH_RESET_HOT); | 528 | eeh_ops->reset(pe, EEH_RESET_HOT); |
551 | 529 | ||
552 | /* The PCI bus requires that the reset be held high for at least | 530 | /* The PCI bus requires that the reset be held high for at least |
553 | * a 100 milliseconds. We wait a bit longer 'just in case'. | 531 | * a 100 milliseconds. We wait a bit longer 'just in case'. |
@@ -559,9 +537,9 @@ static void eeh_reset_pe_once(struct eeh_dev *edev) | |||
559 | * pci slot reset line is dropped. Make sure we don't miss | 537 | * pci slot reset line is dropped. Make sure we don't miss |
560 | * these, and clear the flag now. | 538 | * these, and clear the flag now. |
561 | */ | 539 | */ |
562 | eeh_clear_slot(dn, EEH_MODE_ISOLATED); | 540 | eeh_pe_state_clear(pe, EEH_MODE_ISOLATED); |
563 | 541 | ||
564 | eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); | 542 | eeh_ops->reset(pe, EEH_RESET_DEACTIVATE); |
565 | 543 | ||
566 | /* After a PCI slot has been reset, the PCI Express spec requires | 544 | /* After a PCI slot has been reset, the PCI Express spec requires |
567 | * a 1.5 second idle time for the bus to stabilize, before starting | 545 | * a 1.5 second idle time for the bus to stabilize, before starting |
@@ -573,32 +551,31 @@ static void eeh_reset_pe_once(struct eeh_dev *edev) | |||
573 | 551 | ||
574 | /** | 552 | /** |
575 | * eeh_reset_pe - Reset the indicated PE | 553 | * eeh_reset_pe - Reset the indicated PE |
576 | * @edev: PCI device associated EEH device | 554 | * @pe: EEH PE |
577 | * | 555 | * |
578 | * This routine should be called to reset indicated device, including | 556 | * This routine should be called to reset indicated device, including |
579 | * PE. A PE might include multiple PCI devices and sometimes PCI bridges | 557 | * PE. A PE might include multiple PCI devices and sometimes PCI bridges |
580 | * might be involved as well. | 558 | * might be involved as well. |
581 | */ | 559 | */ |
582 | int eeh_reset_pe(struct eeh_dev *edev) | 560 | int eeh_reset_pe(struct eeh_pe *pe) |
583 | { | 561 | { |
584 | int i, rc; | 562 | int i, rc; |
585 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
586 | 563 | ||
587 | /* Take three shots at resetting the bus */ | 564 | /* Take three shots at resetting the bus */ |
588 | for (i=0; i<3; i++) { | 565 | for (i=0; i<3; i++) { |
589 | eeh_reset_pe_once(edev); | 566 | eeh_reset_pe_once(pe); |
590 | 567 | ||
591 | rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); | 568 | rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); |
592 | if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) | 569 | if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) |
593 | return 0; | 570 | return 0; |
594 | 571 | ||
595 | if (rc < 0) { | 572 | if (rc < 0) { |
596 | printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", | 573 | pr_err("%s: Unrecoverable slot failure on PHB#%d-PE#%x", |
597 | dn->full_name); | 574 | __func__, pe->phb->global_number, pe->addr); |
598 | return -1; | 575 | return -1; |
599 | } | 576 | } |
600 | printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", | 577 | pr_err("EEH: bus reset %d failed on PHB#%d-PE#%x, rc=%d\n", |
601 | i+1, dn->full_name, rc); | 578 | i+1, pe->phb->global_number, pe->addr, rc); |
602 | } | 579 | } |
603 | 580 | ||
604 | return -1; | 581 | return -1; |