diff options
Diffstat (limited to 'arch/powerpc/kernel/eeh.c')
-rw-r--r-- | arch/powerpc/kernel/eeh.c | 49 |
1 files changed, 42 insertions, 7 deletions
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 4bd687d5e7aa..e7b76a6bf150 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
29 | #include <linux/proc_fs.h> | 29 | #include <linux/proc_fs.h> |
30 | #include <linux/rbtree.h> | 30 | #include <linux/rbtree.h> |
31 | #include <linux/reboot.h> | ||
31 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
32 | #include <linux/spinlock.h> | 33 | #include <linux/spinlock.h> |
33 | #include <linux/export.h> | 34 | #include <linux/export.h> |
@@ -84,12 +85,12 @@ | |||
84 | #define EEH_MAX_FAILS 2100000 | 85 | #define EEH_MAX_FAILS 2100000 |
85 | 86 | ||
86 | /* Time to wait for a PCI slot to report status, in milliseconds */ | 87 | /* Time to wait for a PCI slot to report status, in milliseconds */ |
87 | #define PCI_BUS_RESET_WAIT_MSEC (60*1000) | 88 | #define PCI_BUS_RESET_WAIT_MSEC (5*60*1000) |
88 | 89 | ||
89 | /* Platform dependent EEH operations */ | 90 | /* Platform dependent EEH operations */ |
90 | struct eeh_ops *eeh_ops = NULL; | 91 | struct eeh_ops *eeh_ops = NULL; |
91 | 92 | ||
92 | int eeh_subsystem_enabled; | 93 | bool eeh_subsystem_enabled = false; |
93 | EXPORT_SYMBOL(eeh_subsystem_enabled); | 94 | EXPORT_SYMBOL(eeh_subsystem_enabled); |
94 | 95 | ||
95 | /* | 96 | /* |
@@ -364,7 +365,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev) | |||
364 | 365 | ||
365 | eeh_stats.total_mmio_ffs++; | 366 | eeh_stats.total_mmio_ffs++; |
366 | 367 | ||
367 | if (!eeh_subsystem_enabled) | 368 | if (!eeh_enabled()) |
368 | return 0; | 369 | return 0; |
369 | 370 | ||
370 | if (!edev) { | 371 | if (!edev) { |
@@ -747,6 +748,17 @@ int __exit eeh_ops_unregister(const char *name) | |||
747 | return -EEXIST; | 748 | return -EEXIST; |
748 | } | 749 | } |
749 | 750 | ||
751 | static int eeh_reboot_notifier(struct notifier_block *nb, | ||
752 | unsigned long action, void *unused) | ||
753 | { | ||
754 | eeh_set_enable(false); | ||
755 | return NOTIFY_DONE; | ||
756 | } | ||
757 | |||
758 | static struct notifier_block eeh_reboot_nb = { | ||
759 | .notifier_call = eeh_reboot_notifier, | ||
760 | }; | ||
761 | |||
750 | /** | 762 | /** |
751 | * eeh_init - EEH initialization | 763 | * eeh_init - EEH initialization |
752 | * | 764 | * |
@@ -778,6 +790,14 @@ int eeh_init(void) | |||
778 | if (machine_is(powernv) && cnt++ <= 0) | 790 | if (machine_is(powernv) && cnt++ <= 0) |
779 | return ret; | 791 | return ret; |
780 | 792 | ||
793 | /* Register reboot notifier */ | ||
794 | ret = register_reboot_notifier(&eeh_reboot_nb); | ||
795 | if (ret) { | ||
796 | pr_warn("%s: Failed to register notifier (%d)\n", | ||
797 | __func__, ret); | ||
798 | return ret; | ||
799 | } | ||
800 | |||
781 | /* call platform initialization function */ | 801 | /* call platform initialization function */ |
782 | if (!eeh_ops) { | 802 | if (!eeh_ops) { |
783 | pr_warning("%s: Platform EEH operation not found\n", | 803 | pr_warning("%s: Platform EEH operation not found\n", |
@@ -822,7 +842,7 @@ int eeh_init(void) | |||
822 | return ret; | 842 | return ret; |
823 | } | 843 | } |
824 | 844 | ||
825 | if (eeh_subsystem_enabled) | 845 | if (eeh_enabled()) |
826 | pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); | 846 | pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); |
827 | else | 847 | else |
828 | pr_warning("EEH: No capable adapters found\n"); | 848 | pr_warning("EEH: No capable adapters found\n"); |
@@ -897,7 +917,7 @@ void eeh_add_device_late(struct pci_dev *dev) | |||
897 | struct device_node *dn; | 917 | struct device_node *dn; |
898 | struct eeh_dev *edev; | 918 | struct eeh_dev *edev; |
899 | 919 | ||
900 | if (!dev || !eeh_subsystem_enabled) | 920 | if (!dev || !eeh_enabled()) |
901 | return; | 921 | return; |
902 | 922 | ||
903 | pr_debug("EEH: Adding device %s\n", pci_name(dev)); | 923 | pr_debug("EEH: Adding device %s\n", pci_name(dev)); |
@@ -921,6 +941,13 @@ void eeh_add_device_late(struct pci_dev *dev) | |||
921 | eeh_sysfs_remove_device(edev->pdev); | 941 | eeh_sysfs_remove_device(edev->pdev); |
922 | edev->mode &= ~EEH_DEV_SYSFS; | 942 | edev->mode &= ~EEH_DEV_SYSFS; |
923 | 943 | ||
944 | /* | ||
945 | * We definitely should have the PCI device removed | ||
946 | * though it wasn't correctly. So we needn't call | ||
947 | * into error handler afterwards. | ||
948 | */ | ||
949 | edev->mode |= EEH_DEV_NO_HANDLER; | ||
950 | |||
924 | edev->pdev = NULL; | 951 | edev->pdev = NULL; |
925 | dev->dev.archdata.edev = NULL; | 952 | dev->dev.archdata.edev = NULL; |
926 | } | 953 | } |
@@ -998,7 +1025,7 @@ void eeh_remove_device(struct pci_dev *dev) | |||
998 | { | 1025 | { |
999 | struct eeh_dev *edev; | 1026 | struct eeh_dev *edev; |
1000 | 1027 | ||
1001 | if (!dev || !eeh_subsystem_enabled) | 1028 | if (!dev || !eeh_enabled()) |
1002 | return; | 1029 | return; |
1003 | edev = pci_dev_to_eeh_dev(dev); | 1030 | edev = pci_dev_to_eeh_dev(dev); |
1004 | 1031 | ||
@@ -1023,6 +1050,14 @@ void eeh_remove_device(struct pci_dev *dev) | |||
1023 | else | 1050 | else |
1024 | edev->mode |= EEH_DEV_DISCONNECTED; | 1051 | edev->mode |= EEH_DEV_DISCONNECTED; |
1025 | 1052 | ||
1053 | /* | ||
1054 | * We're removing from the PCI subsystem, that means | ||
1055 | * the PCI device driver can't support EEH or not | ||
1056 | * well. So we rely on hotplug completely to do recovery | ||
1057 | * for the specific PCI device. | ||
1058 | */ | ||
1059 | edev->mode |= EEH_DEV_NO_HANDLER; | ||
1060 | |||
1026 | eeh_addr_cache_rmv_dev(dev); | 1061 | eeh_addr_cache_rmv_dev(dev); |
1027 | eeh_sysfs_remove_device(dev); | 1062 | eeh_sysfs_remove_device(dev); |
1028 | edev->mode &= ~EEH_DEV_SYSFS; | 1063 | edev->mode &= ~EEH_DEV_SYSFS; |
@@ -1030,7 +1065,7 @@ void eeh_remove_device(struct pci_dev *dev) | |||
1030 | 1065 | ||
1031 | static int proc_eeh_show(struct seq_file *m, void *v) | 1066 | static int proc_eeh_show(struct seq_file *m, void *v) |
1032 | { | 1067 | { |
1033 | if (0 == eeh_subsystem_enabled) { | 1068 | if (!eeh_enabled()) { |
1034 | seq_printf(m, "EEH Subsystem is globally disabled\n"); | 1069 | seq_printf(m, "EEH Subsystem is globally disabled\n"); |
1035 | seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs); | 1070 | seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs); |
1036 | } else { | 1071 | } else { |