diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_driver.c | 81 |
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 | |||
121 | static 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 | ||
119 | static void eeh_report_reset(struct pci_dev *dev, void *userdata) | 143 | static 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 | ||