diff options
author | Mike Mason <mmlnx@us.ibm.com> | 2009-02-10 06:12:21 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-02-11 00:00:08 -0500 |
commit | 8535ef05a6904429ce72671c3035dbf05e6d5edf (patch) | |
tree | ad7afac47353afc482a5ced7d563d2b7a526b7f7 /arch | |
parent | 10156ceac26b8adfd5d739a3931c8aa9d0d69d53 (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')
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_driver.c | 68 |
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 0ad56ff7b4a..380420f8c40 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 | */ | ||
85 | static 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 | */ | ||
106 | static 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) | |||
174 | static void eeh_report_resume(struct pci_dev *dev, void *userdata) | 202 | static 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 | ||