1 From: Mike Mason <mmlnx@us.ibm.com>
2 Date: Tue, 10 Feb 2009 11:12:21 +0000 (+0000)
3 Subject: powerpc/eeh: Only disable/enable LSI interrupts in EEH
4 Patch-mainline: 2.6.30-rc1
5 Git-commit: 8535ef05a6904429ce72671c3035dbf05e6d5edf
8 powerpc/eeh: Only disable/enable LSI interrupts in EEH
10 The EEH code disables and enables interrupts during the
11 device recovery process. This is unnecessary for MSI
12 and MSI-X interrupts because they are effectively disabled
13 by the DMA Stopped state when an EEH error occurs. The
14 current code is also incorrect for MSI-X interrupts. It
15 doesn't take into account that MSI-X interrupts are tracked
16 in a different way than LSI/MSI interrupts. This patch
17 ensures only LSI interrupts are disabled/enabled.
19 Signed-off-by: Mike Mason <mmlnx@us.ibm.com>
20 Acked-by: Linas Vepstas <linasvepstas@gmail.com>
21 Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
22 Acked-by: Jeff Mahoney <jeffm@suse.com>
25 arch/powerpc/platforms/pseries/eeh_driver.c | 68 ++++++++++++++++++----------
26 1 file changed, 45 insertions(+), 23 deletions(-)
28 --- a/arch/powerpc/platforms/pseries/eeh_driver.c
29 +++ b/arch/powerpc/platforms/pseries/eeh_driver.c
30 @@ -79,6 +79,40 @@ static int irq_in_use(unsigned int irq)
35 + * eeh_disable_irq - disable interrupt for the recovering device
37 +static void eeh_disable_irq(struct pci_dev *dev)
39 + struct device_node *dn = pci_device_to_OF_node(dev);
41 + /* Don't disable MSI and MSI-X interrupts. They are
42 + * effectively disabled by the DMA Stopped state
43 + * when an EEH error occurs.
45 + if (dev->msi_enabled || dev->msix_enabled)
48 + if (!irq_in_use(dev->irq))
51 + PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
52 + disable_irq_nosync(dev->irq);
56 + * eeh_enable_irq - enable interrupt for the recovering device
58 +static void eeh_enable_irq(struct pci_dev *dev)
60 + struct device_node *dn = pci_device_to_OF_node(dev);
62 + if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
63 + PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
64 + enable_irq(dev->irq);
68 /* ------------------------------------------------------- */
70 * eeh_report_error - report pci error to each device driver
71 @@ -98,11 +132,8 @@ static void eeh_report_error(struct pci_
75 - if (irq_in_use (dev->irq)) {
76 - struct device_node *dn = pci_device_to_OF_node(dev);
77 - PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
78 - disable_irq_nosync(dev->irq);
80 + eeh_disable_irq(dev);
82 if (!driver->err_handler ||
83 !driver->err_handler->error_detected)
85 @@ -147,17 +178,14 @@ static void eeh_report_reset(struct pci_
87 enum pci_ers_result rc, *res = userdata;
88 struct pci_driver *driver = dev->driver;
89 - struct device_node *dn = pci_device_to_OF_node(dev);
94 dev->error_state = pci_channel_io_normal;
96 - if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
97 - PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
98 - enable_irq(dev->irq);
100 + eeh_enable_irq(dev);
102 if (!driver->err_handler ||
103 !driver->err_handler->slot_reset)
105 @@ -176,17 +204,14 @@ static void eeh_report_reset(struct pci_
106 static void eeh_report_resume(struct pci_dev *dev, void *userdata)
108 struct pci_driver *driver = dev->driver;
109 - struct device_node *dn = pci_device_to_OF_node(dev);
111 dev->error_state = pci_channel_io_normal;
116 - if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
117 - PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
118 - enable_irq(dev->irq);
120 + eeh_enable_irq(dev);
122 if (!driver->err_handler ||
123 !driver->err_handler->resume)
125 @@ -210,15 +235,12 @@ static void eeh_report_failure(struct pc
129 - if (irq_in_use (dev->irq)) {
130 - struct device_node *dn = pci_device_to_OF_node(dev);
131 - PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
132 - disable_irq_nosync(dev->irq);
134 - if (!driver->err_handler)
136 - if (!driver->err_handler->error_detected)
137 + eeh_disable_irq(dev);
139 + if (!driver->err_handler ||
140 + !driver->err_handler->error_detected)
143 driver->err_handler->error_detected(dev, pci_channel_io_perm_failure);