powerpc/eeh: Only disable/enable LSI interrupts in EEH
authorMike Mason <mmlnx@us.ibm.com>
Tue, 10 Feb 2009 11:12:21 +0000 (11:12 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 11 Feb 2009 05:00:08 +0000 (16:00 +1100)
The EEH code disables and enables interrupts during the
device recovery process.  This is unnecessary for MSI
and MSI-X interrupts because they are effectively disabled
by the DMA Stopped state when an EEH error occurs.  The
current code is also incorrect for MSI-X interrupts.  It
doesn't take into account that MSI-X interrupts are tracked
in a different way than LSI/MSI interrupts.  This patch
ensures only LSI interrupts are disabled/enabled.

Signed-off-by: Mike Mason <mmlnx@us.ibm.com>
Acked-by: Linas Vepstas <linasvepstas@gmail.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/platforms/pseries/eeh_driver.c

index 0ad56ff7b4a04cdd2c024fd4414a39d0f6ac5196..380420f8c4001925eb53e679964d903d5031d3f0 100644 (file)
@@ -79,6 +79,40 @@ static int irq_in_use(unsigned int irq)
        return rc;
 }
 
+/**
+ * eeh_disable_irq - disable interrupt for the recovering device
+ */
+static void eeh_disable_irq(struct pci_dev *dev)
+{
+       struct device_node *dn = pci_device_to_OF_node(dev);
+
+       /* Don't disable MSI and MSI-X interrupts. They are
+        * effectively disabled by the DMA Stopped state
+        * when an EEH error occurs.
+       */
+       if (dev->msi_enabled || dev->msix_enabled)
+               return;
+
+       if (!irq_in_use(dev->irq))
+               return;
+
+       PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
+       disable_irq_nosync(dev->irq);
+}
+
+/**
+ * eeh_enable_irq - enable interrupt for the recovering device
+ */
+static void eeh_enable_irq(struct pci_dev *dev)
+{
+       struct device_node *dn = pci_device_to_OF_node(dev);
+
+       if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
+               PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
+               enable_irq(dev->irq);
+       }
+}
+
 /* ------------------------------------------------------- */
 /**
  * eeh_report_error - report pci error to each device driver
@@ -98,11 +132,8 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata)
        if (!driver)
                return;
 
-       if (irq_in_use (dev->irq)) {
-               struct device_node *dn = pci_device_to_OF_node(dev);
-               PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
-               disable_irq_nosync(dev->irq);
-       }
+       eeh_disable_irq(dev);
+
        if (!driver->err_handler ||
            !driver->err_handler->error_detected)
                return;
@@ -147,15 +178,12 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
 {
        enum pci_ers_result rc, *res = userdata;
        struct pci_driver *driver = dev->driver;
-       struct device_node *dn = pci_device_to_OF_node(dev);
 
        if (!driver)
                return;
 
-       if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
-               PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
-               enable_irq(dev->irq);
-       }
+       eeh_enable_irq(dev);
+
        if (!driver->err_handler ||
            !driver->err_handler->slot_reset)
                return;
@@ -174,17 +202,14 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
 static void eeh_report_resume(struct pci_dev *dev, void *userdata)
 {
        struct pci_driver *driver = dev->driver;
-       struct device_node *dn = pci_device_to_OF_node(dev);
 
        dev->error_state = pci_channel_io_normal;
 
        if (!driver)
                return;
 
-       if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
-               PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
-               enable_irq(dev->irq);
-       }
+       eeh_enable_irq(dev);
+
        if (!driver->err_handler ||
            !driver->err_handler->resume)
                return;
@@ -208,15 +233,12 @@ static void eeh_report_failure(struct pci_dev *dev, void *userdata)
        if (!driver)
                return;
 
-       if (irq_in_use (dev->irq)) {
-               struct device_node *dn = pci_device_to_OF_node(dev);
-               PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
-               disable_irq_nosync(dev->irq);
-       }
-       if (!driver->err_handler)
-               return;
-       if (!driver->err_handler->error_detected)
+       eeh_disable_irq(dev);
+
+       if (!driver->err_handler ||
+           !driver->err_handler->error_detected)
                return;
+
        driver->err_handler->error_detected(dev, pci_channel_io_perm_failure);
 }