Commit 010acfa1 authored by Sam Bobroff's avatar Sam Bobroff Committed by Michael Ellerman

powerpc/eeh: Introduce eeh_set_irq_state()

To ease future refactoring, extract calls to eeh_enable_irq() and
eeh_disable_irq() from the various report functions. This makes
the report functions initial sequences more similar, as well as making
the IRQ changes visible when reading eeh_handle_normal_event().
Signed-off-by: default avatarSam Bobroff <sbobroff@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 47cc8c1c
...@@ -124,22 +124,20 @@ static inline void eeh_pcid_put(struct pci_dev *pdev) ...@@ -124,22 +124,20 @@ static inline void eeh_pcid_put(struct pci_dev *pdev)
* do real work because EEH should freeze DMA transfers for those PCI * do real work because EEH should freeze DMA transfers for those PCI
* devices encountering EEH errors, which includes MSI or MSI-X. * devices encountering EEH errors, which includes MSI or MSI-X.
*/ */
static void eeh_disable_irq(struct pci_dev *dev) static void eeh_disable_irq(struct eeh_dev *edev)
{ {
struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
/* Don't disable MSI and MSI-X interrupts. They are /* Don't disable MSI and MSI-X interrupts. They are
* effectively disabled by the DMA Stopped state * effectively disabled by the DMA Stopped state
* when an EEH error occurs. * when an EEH error occurs.
*/ */
if (dev->msi_enabled || dev->msix_enabled) if (edev->pdev->msi_enabled || edev->pdev->msix_enabled)
return; return;
if (!irq_has_action(dev->irq)) if (!irq_has_action(edev->pdev->irq))
return; return;
edev->mode |= EEH_DEV_IRQ_DISABLED; edev->mode |= EEH_DEV_IRQ_DISABLED;
disable_irq_nosync(dev->irq); disable_irq_nosync(edev->pdev->irq);
} }
/** /**
...@@ -149,10 +147,8 @@ static void eeh_disable_irq(struct pci_dev *dev) ...@@ -149,10 +147,8 @@ static void eeh_disable_irq(struct pci_dev *dev)
* This routine must be called to enable interrupt while failed * This routine must be called to enable interrupt while failed
* device could be resumed. * device could be resumed.
*/ */
static void eeh_enable_irq(struct pci_dev *dev) static void eeh_enable_irq(struct eeh_dev *edev)
{ {
struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
if ((edev->mode) & EEH_DEV_IRQ_DISABLED) { if ((edev->mode) & EEH_DEV_IRQ_DISABLED) {
edev->mode &= ~EEH_DEV_IRQ_DISABLED; edev->mode &= ~EEH_DEV_IRQ_DISABLED;
/* /*
...@@ -175,8 +171,8 @@ static void eeh_enable_irq(struct pci_dev *dev) ...@@ -175,8 +171,8 @@ static void eeh_enable_irq(struct pci_dev *dev)
* *
* tglx * tglx
*/ */
if (irqd_irq_disabled(irq_get_irq_data(dev->irq))) if (irqd_irq_disabled(irq_get_irq_data(edev->pdev->irq)))
enable_irq(dev->irq); enable_irq(edev->pdev->irq);
} }
} }
...@@ -216,6 +212,29 @@ static void eeh_set_channel_state(struct eeh_pe *root, enum pci_channel_state s) ...@@ -216,6 +212,29 @@ static void eeh_set_channel_state(struct eeh_pe *root, enum pci_channel_state s)
edev->pdev->error_state = s; edev->pdev->error_state = s;
} }
static void eeh_set_irq_state(struct eeh_pe *root, bool enable)
{
struct eeh_pe *pe;
struct eeh_dev *edev, *tmp;
eeh_for_each_pe(root, pe) {
eeh_pe_for_each_dev(pe, edev, tmp) {
if (!eeh_edev_actionable(edev))
continue;
if (!eeh_pcid_get(edev->pdev))
continue;
if (enable)
eeh_enable_irq(edev);
else
eeh_disable_irq(edev);
eeh_pcid_put(edev->pdev);
}
}
}
/** /**
* eeh_report_error - Report pci error to each device driver * eeh_report_error - Report pci error to each device driver
* @data: eeh device * @data: eeh device
...@@ -239,8 +258,6 @@ static void *eeh_report_error(struct eeh_dev *edev, void *userdata) ...@@ -239,8 +258,6 @@ static void *eeh_report_error(struct eeh_dev *edev, void *userdata)
driver = eeh_pcid_get(dev); driver = eeh_pcid_get(dev);
if (!driver) goto out_no_dev; if (!driver) goto out_no_dev;
eeh_disable_irq(dev);
if (!driver->err_handler || if (!driver->err_handler ||
!driver->err_handler->error_detected) !driver->err_handler->error_detected)
goto out; goto out;
...@@ -321,8 +338,6 @@ static void *eeh_report_reset(struct eeh_dev *edev, void *userdata) ...@@ -321,8 +338,6 @@ static void *eeh_report_reset(struct eeh_dev *edev, void *userdata)
driver = eeh_pcid_get(dev); driver = eeh_pcid_get(dev);
if (!driver) goto out_no_dev; if (!driver) goto out_no_dev;
eeh_enable_irq(dev);
if (!driver->err_handler || if (!driver->err_handler ||
!driver->err_handler->slot_reset || !driver->err_handler->slot_reset ||
(edev->mode & EEH_DEV_NO_HANDLER) || (edev->mode & EEH_DEV_NO_HANDLER) ||
...@@ -392,7 +407,6 @@ static void *eeh_report_resume(struct eeh_dev *edev, void *userdata) ...@@ -392,7 +407,6 @@ static void *eeh_report_resume(struct eeh_dev *edev, void *userdata)
was_in_error = edev->in_error; was_in_error = edev->in_error;
edev->in_error = false; edev->in_error = false;
eeh_enable_irq(dev);
if (!driver->err_handler || if (!driver->err_handler ||
!driver->err_handler->resume || !driver->err_handler->resume ||
...@@ -437,8 +451,6 @@ static void *eeh_report_failure(struct eeh_dev *edev, void *userdata) ...@@ -437,8 +451,6 @@ static void *eeh_report_failure(struct eeh_dev *edev, void *userdata)
driver = eeh_pcid_get(dev); driver = eeh_pcid_get(dev);
if (!driver) goto out_no_dev; if (!driver) goto out_no_dev;
eeh_disable_irq(dev);
if (!driver->err_handler || if (!driver->err_handler ||
!driver->err_handler->error_detected) !driver->err_handler->error_detected)
goto out; goto out;
...@@ -810,6 +822,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) ...@@ -810,6 +822,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
*/ */
pr_info("EEH: Notify device drivers to shutdown\n"); pr_info("EEH: Notify device drivers to shutdown\n");
eeh_set_channel_state(pe, pci_channel_io_frozen); eeh_set_channel_state(pe, pci_channel_io_frozen);
eeh_set_irq_state(pe, false);
eeh_pe_dev_traverse(pe, eeh_report_error, &result); eeh_pe_dev_traverse(pe, eeh_report_error, &result);
if ((pe->type & EEH_PE_PHB) && if ((pe->type & EEH_PE_PHB) &&
result != PCI_ERS_RESULT_NONE && result != PCI_ERS_RESULT_NONE &&
...@@ -901,6 +914,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) ...@@ -901,6 +914,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
"the completion of reset\n"); "the completion of reset\n");
result = PCI_ERS_RESULT_NONE; result = PCI_ERS_RESULT_NONE;
eeh_set_channel_state(pe, pci_channel_io_normal); eeh_set_channel_state(pe, pci_channel_io_normal);
eeh_set_irq_state(pe, true);
eeh_pe_dev_traverse(pe, eeh_report_reset, &result); eeh_pe_dev_traverse(pe, eeh_report_reset, &result);
} }
...@@ -923,6 +937,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) ...@@ -923,6 +937,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
/* Tell all device drivers that they can resume operations */ /* Tell all device drivers that they can resume operations */
pr_info("EEH: Notify device driver to resume\n"); pr_info("EEH: Notify device driver to resume\n");
eeh_set_channel_state(pe, pci_channel_io_normal); eeh_set_channel_state(pe, pci_channel_io_normal);
eeh_set_irq_state(pe, true);
eeh_pe_dev_traverse(pe, eeh_report_resume, NULL); eeh_pe_dev_traverse(pe, eeh_report_resume, NULL);
pr_info("EEH: Recovery successful.\n"); pr_info("EEH: Recovery successful.\n");
...@@ -942,6 +957,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) ...@@ -942,6 +957,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
/* Notify all devices that they're about to go down. */ /* Notify all devices that they're about to go down. */
eeh_set_channel_state(pe, pci_channel_io_perm_failure); eeh_set_channel_state(pe, pci_channel_io_perm_failure);
eeh_set_irq_state(pe, false);
eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);
/* Mark the PE to be removed permanently */ /* Mark the PE to be removed permanently */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment