diff options
Diffstat (limited to 'arch')
| -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 |
