diff options
author | Linas Vepstas <linas@linas.org> | 2005-11-03 19:50:48 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2005-11-10 00:00:32 -0500 |
commit | d9564ad11454581f85b77026f290f4bb24eecf25 (patch) | |
tree | 33aac0695124ad73a16a9b3d15458c4463804783 /arch/powerpc/platforms | |
parent | 0c95fbb25602caa02ef697c3852cd61f9829e6ff (diff) |
[PATCH] ppc64: mark failed devices
17-eeh-slot-marking-bug.patch
A device that experiences a PCI outage may be just one deivce out
of many that was affected. In order to avoid repeated reports of
a failure, the entire tree of affected devices should be marked
as failed. This patch marks up the entire tree.
Signed-off-by: Linas Vepstas <linas@linas.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh.c | 48 |
1 files changed, 32 insertions, 16 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 3a857b22aa1e..79de2310e70b 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -478,32 +478,47 @@ static struct device_node * find_device_pe(struct device_node *dn) | |||
478 | * an interrupt context, which is bad. | 478 | * an interrupt context, which is bad. |
479 | */ | 479 | */ |
480 | 480 | ||
481 | static void __eeh_mark_slot (struct device_node *dn) | 481 | static void __eeh_mark_slot (struct device_node *dn, int mode_flag) |
482 | { | 482 | { |
483 | while (dn) { | 483 | while (dn) { |
484 | PCI_DN(dn)->eeh_mode |= EEH_MODE_ISOLATED; | 484 | if (PCI_DN(dn)) { |
485 | PCI_DN(dn)->eeh_mode |= mode_flag; | ||
485 | 486 | ||
486 | if (dn->child) | 487 | if (dn->child) |
487 | __eeh_mark_slot (dn->child); | 488 | __eeh_mark_slot (dn->child, mode_flag); |
489 | } | ||
488 | dn = dn->sibling; | 490 | dn = dn->sibling; |
489 | } | 491 | } |
490 | } | 492 | } |
491 | 493 | ||
492 | static void __eeh_clear_slot (struct device_node *dn) | 494 | void eeh_mark_slot (struct device_node *dn, int mode_flag) |
495 | { | ||
496 | dn = find_device_pe (dn); | ||
497 | PCI_DN(dn)->eeh_mode |= mode_flag; | ||
498 | __eeh_mark_slot (dn->child, mode_flag); | ||
499 | } | ||
500 | |||
501 | static void __eeh_clear_slot (struct device_node *dn, int mode_flag) | ||
493 | { | 502 | { |
494 | while (dn) { | 503 | while (dn) { |
495 | PCI_DN(dn)->eeh_mode &= ~EEH_MODE_ISOLATED; | 504 | if (PCI_DN(dn)) { |
496 | if (dn->child) | 505 | PCI_DN(dn)->eeh_mode &= ~mode_flag; |
497 | __eeh_clear_slot (dn->child); | 506 | PCI_DN(dn)->eeh_check_count = 0; |
507 | if (dn->child) | ||
508 | __eeh_clear_slot (dn->child, mode_flag); | ||
509 | } | ||
498 | dn = dn->sibling; | 510 | dn = dn->sibling; |
499 | } | 511 | } |
500 | } | 512 | } |
501 | 513 | ||
502 | static inline void eeh_clear_slot (struct device_node *dn) | 514 | void eeh_clear_slot (struct device_node *dn, int mode_flag) |
503 | { | 515 | { |
504 | unsigned long flags; | 516 | unsigned long flags; |
505 | spin_lock_irqsave(&confirm_error_lock, flags); | 517 | spin_lock_irqsave(&confirm_error_lock, flags); |
506 | __eeh_clear_slot (dn); | 518 | dn = find_device_pe (dn); |
519 | PCI_DN(dn)->eeh_mode &= ~mode_flag; | ||
520 | PCI_DN(dn)->eeh_check_count = 0; | ||
521 | __eeh_clear_slot (dn->child, mode_flag); | ||
507 | spin_unlock_irqrestore(&confirm_error_lock, flags); | 522 | spin_unlock_irqrestore(&confirm_error_lock, flags); |
508 | } | 523 | } |
509 | 524 | ||
@@ -528,7 +543,6 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
528 | int rets[3]; | 543 | int rets[3]; |
529 | unsigned long flags; | 544 | unsigned long flags; |
530 | struct pci_dn *pdn; | 545 | struct pci_dn *pdn; |
531 | struct device_node *pe_dn; | ||
532 | int rc = 0; | 546 | int rc = 0; |
533 | 547 | ||
534 | __get_cpu_var(total_mmio_ffs)++; | 548 | __get_cpu_var(total_mmio_ffs)++; |
@@ -630,8 +644,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
630 | /* Avoid repeated reports of this failure, including problems | 644 | /* Avoid repeated reports of this failure, including problems |
631 | * with other functions on this device, and functions under | 645 | * with other functions on this device, and functions under |
632 | * bridges. */ | 646 | * bridges. */ |
633 | pe_dn = find_device_pe (dn); | 647 | eeh_mark_slot (dn, EEH_MODE_ISOLATED); |
634 | __eeh_mark_slot (pe_dn); | ||
635 | spin_unlock_irqrestore(&confirm_error_lock, flags); | 648 | spin_unlock_irqrestore(&confirm_error_lock, flags); |
636 | 649 | ||
637 | eeh_send_failure_event (dn, dev, rets[0], rets[2]); | 650 | eeh_send_failure_event (dn, dev, rets[0], rets[2]); |
@@ -743,9 +756,6 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state) | |||
743 | rc, state, pdn->node->full_name); | 756 | rc, state, pdn->node->full_name); |
744 | return; | 757 | return; |
745 | } | 758 | } |
746 | |||
747 | if (state == 0) | ||
748 | eeh_clear_slot (pdn->node->parent->child); | ||
749 | } | 759 | } |
750 | 760 | ||
751 | /** rtas_set_slot_reset -- assert the pci #RST line for 1/4 second | 761 | /** rtas_set_slot_reset -- assert the pci #RST line for 1/4 second |
@@ -764,6 +774,12 @@ rtas_set_slot_reset(struct pci_dn *pdn) | |||
764 | 774 | ||
765 | #define PCI_BUS_RST_HOLD_TIME_MSEC 250 | 775 | #define PCI_BUS_RST_HOLD_TIME_MSEC 250 |
766 | msleep (PCI_BUS_RST_HOLD_TIME_MSEC); | 776 | msleep (PCI_BUS_RST_HOLD_TIME_MSEC); |
777 | |||
778 | /* We might get hit with another EEH freeze as soon as the | ||
779 | * pci slot reset line is dropped. Make sure we don't miss | ||
780 | * these, and clear the flag now. */ | ||
781 | eeh_clear_slot (pdn->node, EEH_MODE_ISOLATED); | ||
782 | |||
767 | rtas_pci_slot_reset (pdn, 0); | 783 | rtas_pci_slot_reset (pdn, 0); |
768 | 784 | ||
769 | /* After a PCI slot has been reset, the PCI Express spec requires | 785 | /* After a PCI slot has been reset, the PCI Express spec requires |