Skip to content

Commit

Permalink
powerpc/eeh: Only disable/enable LSI interrupts in EEH
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mike Mason authored and Benjamin Herrenschmidt committed Feb 11, 2009
1 parent 10156ce commit 8535ef0
Showing 1 changed file with 45 additions and 23 deletions.
68 changes: 45 additions & 23 deletions arch/powerpc/platforms/pseries/eeh_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
}

Expand Down

0 comments on commit 8535ef0

Please sign in to comment.