aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinas Vepstas <linas@austin.ibm.com>2006-09-15 19:58:59 -0400
committerPaul Mackerras <paulus@samba.org>2006-09-21 08:59:20 -0400
commit6a1ca373a16b0e170164ab8a2d6d01eab2a22f6e (patch)
tree94408b9a75b9a031fb3dfaf18c4dd192de4fb448
parent47b5c838af92d3504e99633bf568578203b7305f (diff)
[POWERPC] EEH: support MMIO enable recovery step
Update to the PowerPC PCI error recovery code. Add code to enable MMIO if a device driver reports that it is capable of recovering on its own. One anticipated use of this having a device driver enable MMIO so that it can take a register dump, which might then be followed by the device driver requesting a full reset. Signed-off-by: Linas Vepstas <linas@austin.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c81
1 files changed, 64 insertions, 17 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 045cd7a37339..c2bc9904f1cb 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -100,14 +100,38 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata)
100 PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; 100 PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
101 disable_irq_nosync(dev->irq); 101 disable_irq_nosync(dev->irq);
102 } 102 }
103 if (!driver->err_handler) 103 if (!driver->err_handler ||
104 return; 104 !driver->err_handler->error_detected)
105 if (!driver->err_handler->error_detected)
106 return; 105 return;
107 106
108 rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen); 107 rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen);
109 if (*res == PCI_ERS_RESULT_NONE) *res = rc; 108 if (*res == PCI_ERS_RESULT_NONE) *res = rc;
110 if (*res == PCI_ERS_RESULT_NEED_RESET) return; 109 if (*res == PCI_ERS_RESULT_DISCONNECT &&
110 rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
111}
112
113/**
114 * eeh_report_mmio_enabled - tell drivers that MMIO has been enabled
115 *
116 * Report an EEH error to each device driver, collect up and
117 * merge the device driver responses. Cumulative response
118 * passed back in "userdata".
119 */
120
121static void eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
122{
123 enum pci_ers_result rc, *res = userdata;
124 struct pci_driver *driver = dev->driver;
125
126 // dev->error_state = pci_channel_mmio_enabled;
127
128 if (!driver ||
129 !driver->err_handler ||
130 !driver->err_handler->mmio_enabled)
131 return;
132
133 rc = driver->err_handler->mmio_enabled (dev);
134 if (*res == PCI_ERS_RESULT_NONE) *res = rc;
111 if (*res == PCI_ERS_RESULT_DISCONNECT && 135 if (*res == PCI_ERS_RESULT_DISCONNECT &&
112 rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; 136 rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
113} 137}
@@ -118,6 +142,7 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata)
118 142
119static void eeh_report_reset(struct pci_dev *dev, void *userdata) 143static void eeh_report_reset(struct pci_dev *dev, void *userdata)
120{ 144{
145 enum pci_ers_result rc, *res = userdata;
121 struct pci_driver *driver = dev->driver; 146 struct pci_driver *driver = dev->driver;
122 struct device_node *dn = pci_device_to_OF_node(dev); 147 struct device_node *dn = pci_device_to_OF_node(dev);
123 148
@@ -128,12 +153,14 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
128 PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; 153 PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
129 enable_irq(dev->irq); 154 enable_irq(dev->irq);
130 } 155 }
131 if (!driver->err_handler) 156 if (!driver->err_handler ||
132 return; 157 !driver->err_handler->slot_reset)
133 if (!driver->err_handler->slot_reset)
134 return; 158 return;
135 159
136 driver->err_handler->slot_reset(dev); 160 rc = driver->err_handler->slot_reset(dev);
161 if (*res == PCI_ERS_RESULT_NONE) *res = rc;
162 if (*res == PCI_ERS_RESULT_DISCONNECT &&
163 rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
137} 164}
138 165
139/** 166/**
@@ -362,23 +389,43 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
362 goto hard_fail; 389 goto hard_fail;
363 } 390 }
364 391
365 /* If any device called out for a reset, then reset the slot */ 392 /* If all devices reported they can proceed, then re-enable MMIO */
366 if (result == PCI_ERS_RESULT_NEED_RESET) { 393 if (result == PCI_ERS_RESULT_CAN_RECOVER) {
367 rc = eeh_reset_device(frozen_pdn, NULL); 394 rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO);
368 if (rc) 395
369 goto hard_fail; 396 if (rc) {
370 pci_walk_bus(frozen_bus, eeh_report_reset, NULL); 397 result = PCI_ERS_RESULT_NEED_RESET;
398 } else {
399 result = PCI_ERS_RESULT_NONE;
400 pci_walk_bus(frozen_bus, eeh_report_mmio_enabled, &result);
401 }
371 } 402 }
372 403
373 /* If all devices reported they can proceed, the re-enable PIO */ 404 /* If all devices reported they can proceed, then re-enable DMA */
374 if (result == PCI_ERS_RESULT_CAN_RECOVER) { 405 if (result == PCI_ERS_RESULT_CAN_RECOVER) {
375 /* XXX Not supported; we brute-force reset the device */ 406 rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA);
407
408 if (rc)
409 result = PCI_ERS_RESULT_NEED_RESET;
410 }
411
412 /* If any device has a hard failure, then shut off everything. */
413 if (result == PCI_ERS_RESULT_DISCONNECT)
414 goto hard_fail;
415
416 /* If any device called out for a reset, then reset the slot */
417 if (result == PCI_ERS_RESULT_NEED_RESET) {
376 rc = eeh_reset_device(frozen_pdn, NULL); 418 rc = eeh_reset_device(frozen_pdn, NULL);
377 if (rc) 419 if (rc)
378 goto hard_fail; 420 goto hard_fail;
379 pci_walk_bus(frozen_bus, eeh_report_reset, NULL); 421 result = PCI_ERS_RESULT_NONE;
422 pci_walk_bus(frozen_bus, eeh_report_reset, &result);
380 } 423 }
381 424
425 /* All devices should claim they have recovered by now. */
426 if (result != PCI_ERS_RESULT_RECOVERED)
427 goto hard_fail;
428
382 /* Tell all device drivers that they can resume operations */ 429 /* Tell all device drivers that they can resume operations */
383 pci_walk_bus(frozen_bus, eeh_report_resume, NULL); 430 pci_walk_bus(frozen_bus, eeh_report_resume, NULL);
384 431