aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/eeh.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/eeh.c')
-rw-r--r--arch/powerpc/kernel/eeh.c49
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 */
90struct eeh_ops *eeh_ops = NULL; 91struct eeh_ops *eeh_ops = NULL;
91 92
92int eeh_subsystem_enabled; 93bool eeh_subsystem_enabled = false;
93EXPORT_SYMBOL(eeh_subsystem_enabled); 94EXPORT_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
751static 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
758static 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
1031static int proc_eeh_show(struct seq_file *m, void *v) 1066static 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 {