diff options
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh.c | 48 | ||||
-rw-r--r-- | include/asm-powerpc/ppc-pci.h | 7 |
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 | ||
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 |
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 | ||
88 | int rtas_write_config(struct pci_dn *, int where, int size, u32 val); | 88 | int 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 | */ | ||
94 | void eeh_mark_slot (struct device_node *dn, int mode_flag); | ||
95 | void 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 */ |