diff options
author | Richard A Lary <rlary@linux.vnet.ibm.com> | 2011-04-22 05:59:47 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-05-04 02:02:36 -0400 |
commit | 308fc4f8e10b5239cde46104bb9fca79b46230c8 (patch) | |
tree | 34b0db6cf863af99453094a922c071c44b46450e /arch/powerpc/platforms | |
parent | 9ee820fa005254dfc816330f6654f14dcb2beee1 (diff) |
powerpc/pseries/eeh: Propagate needs_freset flag to device at PE
For multifunction adapters with a PCI bridge or switch as the device
at the Partitionable Endpoint(PE), if one or more devices below PE
sets dev->needs_freset, that value will be set for the PE device.
In other words, if any device below PE requires a fundamental reset
the PE will request a fundamental reset.
Signed-off-by: Richard A Lary <rlary@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 | 50 |
1 files changed, 43 insertions, 7 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 229373053864..6cb3e7bd175d 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -451,6 +451,39 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag) | |||
451 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); | 451 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); |
452 | } | 452 | } |
453 | 453 | ||
454 | void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) | ||
455 | { | ||
456 | struct device_node *dn; | ||
457 | |||
458 | for_each_child_of_node(parent, dn) { | ||
459 | if (PCI_DN(dn)) { | ||
460 | |||
461 | struct pci_dev *dev = PCI_DN(dn)->pcidev; | ||
462 | |||
463 | if (dev && dev->driver) | ||
464 | *freset |= dev->needs_freset; | ||
465 | |||
466 | __eeh_set_pe_freset(dn, freset); | ||
467 | } | ||
468 | } | ||
469 | } | ||
470 | |||
471 | void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) | ||
472 | { | ||
473 | struct pci_dev *dev; | ||
474 | dn = find_device_pe(dn); | ||
475 | |||
476 | /* Back up one, since config addrs might be shared */ | ||
477 | if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) | ||
478 | dn = dn->parent; | ||
479 | |||
480 | dev = PCI_DN(dn)->pcidev; | ||
481 | if (dev) | ||
482 | *freset |= dev->needs_freset; | ||
483 | |||
484 | __eeh_set_pe_freset(dn, freset); | ||
485 | } | ||
486 | |||
454 | /** | 487 | /** |
455 | * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze | 488 | * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze |
456 | * @dn device node | 489 | * @dn device node |
@@ -739,18 +772,21 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat | |||
739 | /** | 772 | /** |
740 | * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second | 773 | * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second |
741 | * @pdn: pci device node to be reset. | 774 | * @pdn: pci device node to be reset. |
742 | * | ||
743 | * Return 0 if success, else a non-zero value. | ||
744 | */ | 775 | */ |
745 | 776 | ||
746 | static void __rtas_set_slot_reset(struct pci_dn *pdn) | 777 | static void __rtas_set_slot_reset(struct pci_dn *pdn) |
747 | { | 778 | { |
748 | struct pci_dev *dev = pdn->pcidev; | 779 | unsigned int freset = 0; |
749 | 780 | ||
750 | /* Determine type of EEH reset required by device, | 781 | /* Determine type of EEH reset required for |
751 | * default hot reset or fundamental reset | 782 | * Partitionable Endpoint, a hot-reset (1) |
752 | */ | 783 | * or a fundamental reset (3). |
753 | if (dev && dev->needs_freset) | 784 | * A fundamental reset required by any device under |
785 | * Partitionable Endpoint trumps hot-reset. | ||
786 | */ | ||
787 | eeh_set_pe_freset(pdn->node, &freset); | ||
788 | |||
789 | if (freset) | ||
754 | rtas_pci_slot_reset(pdn, 3); | 790 | rtas_pci_slot_reset(pdn, 3); |
755 | else | 791 | else |
756 | rtas_pci_slot_reset(pdn, 1); | 792 | rtas_pci_slot_reset(pdn, 1); |