powerpc/eeh: Allow to disable EEH
authorGavin Shan <gwshan@linux.vnet.ibm.com>
Thu, 24 Apr 2014 08:00:18 +0000 (18:00 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 28 Apr 2014 07:34:27 +0000 (17:34 +1000)
The patch introduces bootarg "eeh=off" to disable EEH functinality.
Also, it creates /sys/kerenl/debug/powerpc/eeh_enable to disable
or enable EEH functionality. By default, we have the functionality
enabled.

For PowerNV platform, we will restore to have the conventional
mechanism of clearing frozen PE during PCI config access if we're
going to disable EEH functionality. Conversely, we will rely on
EEH for error recovery.

The patch also fixes the issue that we missed to cover the case
of disabled EEH functionality in function ioda_eeh_event(). Those
events driven by interrupt should be cleared to avoid endless
reporting.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/kernel/eeh.c
arch/powerpc/platforms/powernv/eeh-ioda.c
arch/powerpc/platforms/powernv/pci.h

index 06d2b7c6b661e50fddc8b1d39cd8a58cc3da4611..1e409a2ff88bd7e5ddfb53ff006c0ed1439ad6a5 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/debugfs.h>
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -132,6 +133,15 @@ static struct eeh_stats eeh_stats;
 
 #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE)
 
+static int __init eeh_setup(char *str)
+{
+       if (!strcmp(str, "off"))
+               eeh_subsystem_flags |= EEH_FORCE_DISABLED;
+
+       return 1;
+}
+__setup("eeh=", eeh_setup);
+
 /**
  * eeh_gather_pci_data - Copy assorted PCI config space registers to buff
  * @edev: device to report data for
@@ -1117,10 +1127,45 @@ static const struct file_operations proc_eeh_operations = {
        .release   = single_release,
 };
 
+#ifdef CONFIG_DEBUG_FS
+static int eeh_enable_dbgfs_set(void *data, u64 val)
+{
+       if (val)
+               eeh_subsystem_flags &= ~EEH_FORCE_DISABLED;
+       else
+               eeh_subsystem_flags |= EEH_FORCE_DISABLED;
+
+       /* Notify the backend */
+       if (eeh_ops->post_init)
+               eeh_ops->post_init();
+
+       return 0;
+}
+
+static int eeh_enable_dbgfs_get(void *data, u64 *val)
+{
+       if (eeh_enabled())
+               *val = 0x1ul;
+       else
+               *val = 0x0ul;
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(eeh_enable_dbgfs_ops, eeh_enable_dbgfs_get,
+                       eeh_enable_dbgfs_set, "0x%llx\n");
+#endif
+
 static int __init eeh_init_proc(void)
 {
-       if (machine_is(pseries) || machine_is(powernv))
+       if (machine_is(pseries) || machine_is(powernv)) {
                proc_create("powerpc/eeh", 0, NULL, &proc_eeh_operations);
+#ifdef CONFIG_DEBUG_FS
+               debugfs_create_file("eeh_enable", 0600,
+                                    powerpc_debugfs_root, NULL,
+                                    &eeh_enable_dbgfs_ops);
+#endif
+       }
+
        return 0;
 }
 __initcall(eeh_init_proc);
index 6bdae8d84463f2fcc66d11c93760bef4f24bd15b..35ec394f784f3585aaa0651e680e07541879a883 100644 (file)
@@ -42,11 +42,19 @@ static int ioda_eeh_event(struct notifier_block *nb,
 {
        uint64_t changed_evts = (uint64_t)change;
 
-       /* We simply send special EEH event */
-       if ((changed_evts & OPAL_EVENT_PCI_ERROR) &&
-           (events & OPAL_EVENT_PCI_ERROR) &&
-           eeh_enabled())
+       /*
+        * We simply send special EEH event if EEH has
+        * been enabled, or clear pending events in
+        * case that we enable EEH soon
+        */
+       if (!(changed_evts & OPAL_EVENT_PCI_ERROR) ||
+           !(events & OPAL_EVENT_PCI_ERROR))
+               return 0;
+
+       if (eeh_enabled())
                eeh_send_failure_event(NULL);
+       else
+               opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
 
        return 0;
 }
@@ -141,7 +149,9 @@ static int ioda_eeh_post_init(struct pci_controller *hose)
        }
 
 #ifdef CONFIG_DEBUG_FS
-       if (phb->dbgfs) {
+       if (!phb->has_dbgfs && phb->dbgfs) {
+               phb->has_dbgfs = 1;
+
                debugfs_create_file("err_injct_outbound", 0600,
                                    phb->dbgfs, hose,
                                    &ioda_eeh_outb_dbgfs_ops);
@@ -154,7 +164,14 @@ static int ioda_eeh_post_init(struct pci_controller *hose)
        }
 #endif
 
-       phb->flags |= PNV_PHB_FLAG_EEH;
+       /* If EEH is enabled, we're going to rely on that.
+        * Otherwise, we restore to conventional mechanism
+        * to clear frozen PE during PCI config access.
+        */
+       if (eeh_enabled())
+               phb->flags |= PNV_PHB_FLAG_EEH;
+       else
+               phb->flags &= ~PNV_PHB_FLAG_EEH;
 
        return 0;
 }
index 94e3495b7f2b87e201b68a8c0aa26227858e9364..39ec6978e8092e852dfe3b28c3a371ebb9f97b18 100644 (file)
@@ -101,6 +101,7 @@ struct pnv_phb {
 #endif
 
 #ifdef CONFIG_DEBUG_FS
+       int                     has_dbgfs;
        struct dentry           *dbgfs;
 #endif