diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/eeh.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh.c | 82 |
1 files changed, 69 insertions, 13 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 89649173d3a3..46b55cf563e3 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -93,6 +93,7 @@ static int ibm_slot_error_detail; | |||
93 | static int ibm_get_config_addr_info; | 93 | static int ibm_get_config_addr_info; |
94 | static int ibm_get_config_addr_info2; | 94 | static int ibm_get_config_addr_info2; |
95 | static int ibm_configure_bridge; | 95 | static int ibm_configure_bridge; |
96 | static int ibm_configure_pe; | ||
96 | 97 | ||
97 | int eeh_subsystem_enabled; | 98 | int eeh_subsystem_enabled; |
98 | EXPORT_SYMBOL(eeh_subsystem_enabled); | 99 | EXPORT_SYMBOL(eeh_subsystem_enabled); |
@@ -261,6 +262,8 @@ void eeh_slot_error_detail(struct pci_dn *pdn, int severity) | |||
261 | pci_regs_buf[0] = 0; | 262 | pci_regs_buf[0] = 0; |
262 | 263 | ||
263 | rtas_pci_enable(pdn, EEH_THAW_MMIO); | 264 | rtas_pci_enable(pdn, EEH_THAW_MMIO); |
265 | rtas_configure_bridge(pdn); | ||
266 | eeh_restore_bars(pdn); | ||
264 | loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); | 267 | loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); |
265 | 268 | ||
266 | rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen); | 269 | rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen); |
@@ -448,6 +451,39 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag) | |||
448 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); | 451 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); |
449 | } | 452 | } |
450 | 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 | |||
451 | /** | 487 | /** |
452 | * 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 |
453 | * @dn device node | 489 | * @dn device node |
@@ -692,15 +728,24 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state) | |||
692 | if (pdn->eeh_pe_config_addr) | 728 | if (pdn->eeh_pe_config_addr) |
693 | config_addr = pdn->eeh_pe_config_addr; | 729 | config_addr = pdn->eeh_pe_config_addr; |
694 | 730 | ||
695 | rc = rtas_call(ibm_set_slot_reset,4,1, NULL, | 731 | rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, |
696 | config_addr, | 732 | config_addr, |
697 | BUID_HI(pdn->phb->buid), | 733 | BUID_HI(pdn->phb->buid), |
698 | BUID_LO(pdn->phb->buid), | 734 | BUID_LO(pdn->phb->buid), |
699 | state); | 735 | state); |
700 | if (rc) | 736 | |
701 | printk (KERN_WARNING "EEH: Unable to reset the failed slot," | 737 | /* Fundamental-reset not supported on this PE, try hot-reset */ |
702 | " (%d) #RST=%d dn=%s\n", | 738 | if (rc == -8 && state == 3) { |
703 | rc, state, pdn->node->full_name); | 739 | rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, |
740 | config_addr, | ||
741 | BUID_HI(pdn->phb->buid), | ||
742 | BUID_LO(pdn->phb->buid), 1); | ||
743 | if (rc) | ||
744 | printk(KERN_WARNING | ||
745 | "EEH: Unable to reset the failed slot," | ||
746 | " #RST=%d dn=%s\n", | ||
747 | rc, pdn->node->full_name); | ||
748 | } | ||
704 | } | 749 | } |
705 | 750 | ||
706 | /** | 751 | /** |
@@ -736,18 +781,21 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat | |||
736 | /** | 781 | /** |
737 | * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second | 782 | * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second |
738 | * @pdn: pci device node to be reset. | 783 | * @pdn: pci device node to be reset. |
739 | * | ||
740 | * Return 0 if success, else a non-zero value. | ||
741 | */ | 784 | */ |
742 | 785 | ||
743 | static void __rtas_set_slot_reset(struct pci_dn *pdn) | 786 | static void __rtas_set_slot_reset(struct pci_dn *pdn) |
744 | { | 787 | { |
745 | struct pci_dev *dev = pdn->pcidev; | 788 | unsigned int freset = 0; |
746 | 789 | ||
747 | /* Determine type of EEH reset required by device, | 790 | /* Determine type of EEH reset required for |
748 | * default hot reset or fundamental reset | 791 | * Partitionable Endpoint, a hot-reset (1) |
749 | */ | 792 | * or a fundamental reset (3). |
750 | if (dev && dev->needs_freset) | 793 | * A fundamental reset required by any device under |
794 | * Partitionable Endpoint trumps hot-reset. | ||
795 | */ | ||
796 | eeh_set_pe_freset(pdn->node, &freset); | ||
797 | |||
798 | if (freset) | ||
751 | rtas_pci_slot_reset(pdn, 3); | 799 | rtas_pci_slot_reset(pdn, 3); |
752 | else | 800 | else |
753 | rtas_pci_slot_reset(pdn, 1); | 801 | rtas_pci_slot_reset(pdn, 1); |
@@ -895,13 +943,20 @@ rtas_configure_bridge(struct pci_dn *pdn) | |||
895 | { | 943 | { |
896 | int config_addr; | 944 | int config_addr; |
897 | int rc; | 945 | int rc; |
946 | int token; | ||
898 | 947 | ||
899 | /* Use PE configuration address, if present */ | 948 | /* Use PE configuration address, if present */ |
900 | config_addr = pdn->eeh_config_addr; | 949 | config_addr = pdn->eeh_config_addr; |
901 | if (pdn->eeh_pe_config_addr) | 950 | if (pdn->eeh_pe_config_addr) |
902 | config_addr = pdn->eeh_pe_config_addr; | 951 | config_addr = pdn->eeh_pe_config_addr; |
903 | 952 | ||
904 | rc = rtas_call(ibm_configure_bridge,3,1, NULL, | 953 | /* Use new configure-pe function, if supported */ |
954 | if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) | ||
955 | token = ibm_configure_pe; | ||
956 | else | ||
957 | token = ibm_configure_bridge; | ||
958 | |||
959 | rc = rtas_call(token, 3, 1, NULL, | ||
905 | config_addr, | 960 | config_addr, |
906 | BUID_HI(pdn->phb->buid), | 961 | BUID_HI(pdn->phb->buid), |
907 | BUID_LO(pdn->phb->buid)); | 962 | BUID_LO(pdn->phb->buid)); |
@@ -1077,6 +1132,7 @@ void __init eeh_init(void) | |||
1077 | ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); | 1132 | ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); |
1078 | ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); | 1133 | ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); |
1079 | ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); | 1134 | ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); |
1135 | ibm_configure_pe = rtas_token("ibm,configure-pe"); | ||
1080 | 1136 | ||
1081 | if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) | 1137 | if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) |
1082 | return; | 1138 | return; |