aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinas Vepstas <linas@linas.org>2005-11-03 19:50:48 -0500
committerPaul Mackerras <paulus@samba.org>2005-11-10 00:00:32 -0500
commitd9564ad11454581f85b77026f290f4bb24eecf25 (patch)
tree33aac0695124ad73a16a9b3d15458c4463804783
parent0c95fbb25602caa02ef697c3852cd61f9829e6ff (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>
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c48
-rw-r--r--include/asm-powerpc/ppc-pci.h7
2 files changed, 39 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
481static void __eeh_mark_slot (struct device_node *dn) 481static 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
492static void __eeh_clear_slot (struct device_node *dn) 494void 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
501static 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
502static inline void eeh_clear_slot (struct device_node *dn) 514void 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
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index d86c47872bea..9896fade98a7 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -87,6 +87,13 @@ void rtas_configure_bridge(struct pci_dn *);
87 87
88int rtas_write_config(struct pci_dn *, int where, int size, u32 val); 88int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
89 89
90/**
91 * mark and clear slots: find "partition endpoint" PE and set or
92 * clear the flags for each subnode of the PE.
93 */
94void eeh_mark_slot (struct device_node *dn, int mode_flag);
95void eeh_clear_slot (struct device_node *dn, int mode_flag);
96
90#endif 97#endif
91 98
92#endif /* _ASM_POWERPC_PPC_PCI_H */ 99#endif /* _ASM_POWERPC_PPC_PCI_H */