aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pseries/eeh_driver.c
diff options
context:
space:
mode:
authorMike Mason <mmlnx@us.ibm.com>2009-02-10 06:12:21 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-02-11 00:00:08 -0500
commit8535ef05a6904429ce72671c3035dbf05e6d5edf (patch)
treead7afac47353afc482a5ced7d563d2b7a526b7f7 /arch/powerpc/platforms/pseries/eeh_driver.c
parent10156ceac26b8adfd5d739a3931c8aa9d0d69d53 (diff)
powerpc/eeh: Only disable/enable LSI interrupts in EEH
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>
Diffstat (limited to 'arch/powerpc/platforms/pseries/eeh_driver.c')
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c68
1 files changed, 45 insertions, 23 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 0ad56ff7b4a0..380420f8c400 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -79,6 +79,40 @@ static int irq_in_use(unsigned int irq)
79 return rc; 79 return rc;
80} 80}
81 81
82/**
83 * eeh_disable_irq - disable interrupt for the recovering device
84 */
85static void eeh_disable_irq(struct pci_dev *dev)
86{
87 struct device_node *dn = pci_device_to_OF_node(dev);
88
89 /* Don't disable MSI and MSI-X interrupts. They are
90 * effectively disabled by the DMA Stopped state
91 * when an EEH error occurs.
92 */
93 if (dev->msi_enabled || dev->msix_enabled)
94 return;
95
96 if (!irq_in_use(dev->irq))
97 return;
98
99 PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
100 disable_irq_nosync(dev->irq);
101}
102
103/**
104 * eeh_enable_irq - enable interrupt for the recovering device
105 */
106static void eeh_enable_irq(struct pci_dev *dev)
107{
108 struct device_node *dn = pci_device_to_OF_node(dev);
109
110 if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
111 PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
112 enable_irq(dev->irq);
113 }
114}
115
82/* ------------------------------------------------------- */ 116/* ------------------------------------------------------- */
83/** 117/**
84 * eeh_report_error - report pci error to each device driver 118 * 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)
98 if (!driver) 132 if (!driver)
99 return; 133 return;
100 134
101 if (irq_in_use (dev->irq)) { 135 eeh_disable_irq(dev);
102 struct device_node *dn = pci_device_to_OF_node(dev); 136
103 PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
104 disable_irq_nosync(dev->irq);
105 }
106 if (!driver->err_handler || 137 if (!driver->err_handler ||
107 !driver->err_handler->error_detected) 138 !driver->err_handler->error_detected)
108 return; 139 return;
@@ -147,15 +178,12 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
147{ 178{
148 enum pci_ers_result rc, *res = userdata; 179 enum pci_ers_result rc, *res = userdata;
149 struct pci_driver *driver = dev->driver; 180 struct pci_driver *driver = dev->driver;
150 struct device_node *dn = pci_device_to_OF_node(dev);
151 181
152 if (!driver) 182 if (!driver)
153 return; 183 return;
154 184
155 if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { 185 eeh_enable_irq(dev);
156 PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; 186
157 enable_irq(dev->irq);
158 }
159 if (!driver->err_handler || 187 if (!driver->err_handler ||
160 !driver->err_handler->slot_reset) 188 !driver->err_handler->slot_reset)
161 return; 189 return;
@@ -174,17 +202,14 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
174static void eeh_report_resume(struct pci_dev *dev, void *userdata) 202static void eeh_report_resume(struct pci_dev *dev, void *userdata)
175{ 203{
176 struct pci_driver *driver = dev->driver; 204 struct pci_driver *driver = dev->driver;
177 struct device_node *dn = pci_device_to_OF_node(dev);
178 205
179 dev->error_state = pci_channel_io_normal; 206 dev->error_state = pci_channel_io_normal;
180 207
181 if (!driver) 208 if (!driver)
182 return; 209 return;
183 210
184 if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { 211 eeh_enable_irq(dev);
185 PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; 212
186 enable_irq(dev->irq);
187 }
188 if (!driver->err_handler || 213 if (!driver->err_handler ||
189 !driver->err_handler->resume) 214 !driver->err_handler->resume)
190 return; 215 return;
@@ -208,15 +233,12 @@ static void eeh_report_failure(struct pci_dev *dev, void *userdata)
208 if (!driver) 233 if (!driver)
209 return; 234 return;
210 235
211 if (irq_in_use (dev->irq)) { 236 eeh_disable_irq(dev);
212 struct device_node *dn = pci_device_to_OF_node(dev); 237
213 PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; 238 if (!driver->err_handler ||
214 disable_irq_nosync(dev->irq); 239 !driver->err_handler->error_detected)
215 }
216 if (!driver->err_handler)
217 return;
218 if (!driver->err_handler->error_detected)
219 return; 240 return;
241
220 driver->err_handler->error_detected(dev, pci_channel_io_perm_failure); 242 driver->err_handler->error_detected(dev, pci_channel_io_perm_failure);
221} 243}
222 244