|
34 | 34 |
|
35 | 35 | #include "powernv.h"
|
36 | 36 | #include "pci.h"
|
| 37 | +#include "../../../../drivers/pci/pci.h" |
37 | 38 |
|
38 | 39 | static int eeh_event_irq = -EINVAL;
|
39 | 40 |
|
@@ -849,7 +850,7 @@ static int __pnv_eeh_bridge_reset(struct pci_dev *dev, int option)
|
849 | 850 | int aer = edev ? edev->aer_cap : 0;
|
850 | 851 | u32 ctrl;
|
851 | 852 |
|
852 |
| - pr_debug("%s: Reset PCI bus %04x:%02x with option %d\n", |
| 853 | + pr_debug("%s: Secondary Reset PCI bus %04x:%02x with option %d\n", |
853 | 854 | __func__, pci_domain_nr(dev->bus),
|
854 | 855 | dev->bus->number, option);
|
855 | 856 |
|
@@ -907,6 +908,10 @@ static int pnv_eeh_bridge_reset(struct pci_dev *pdev, int option)
|
907 | 908 | if (!dn || !of_get_property(dn, "ibm,reset-by-firmware", NULL))
|
908 | 909 | return __pnv_eeh_bridge_reset(pdev, option);
|
909 | 910 |
|
| 911 | + pr_debug("%s: FW reset PCI bus %04x:%02x with option %d\n", |
| 912 | + __func__, pci_domain_nr(pdev->bus), |
| 913 | + pdev->bus->number, option); |
| 914 | + |
910 | 915 | switch (option) {
|
911 | 916 | case EEH_RESET_FUNDAMENTAL:
|
912 | 917 | scope = OPAL_RESET_PCI_FUNDAMENTAL;
|
@@ -1125,10 +1130,37 @@ static int pnv_eeh_reset(struct eeh_pe *pe, int option)
|
1125 | 1130 | return -EIO;
|
1126 | 1131 | }
|
1127 | 1132 |
|
1128 |
| - if (pci_is_root_bus(bus) || |
1129 |
| - pci_is_root_bus(bus->parent)) |
| 1133 | + if (pci_is_root_bus(bus)) |
1130 | 1134 | return pnv_eeh_root_reset(hose, option);
|
1131 | 1135 |
|
| 1136 | + /* |
| 1137 | + * For hot resets try use the generic PCI error recovery reset |
| 1138 | + * functions. These correctly handles the case where the secondary |
| 1139 | + * bus is behind a hotplug slot and it will use the slot provided |
| 1140 | + * reset methods to prevent spurious hotplug events during the reset. |
| 1141 | + * |
| 1142 | + * Fundemental resets need to be handled internally to EEH since the |
| 1143 | + * PCI core doesn't really have a concept of a fundemental reset, |
| 1144 | + * mainly because there's no standard way to generate one. Only a |
| 1145 | + * few devices require an FRESET so it should be fine. |
| 1146 | + */ |
| 1147 | + if (option != EEH_RESET_FUNDAMENTAL) { |
| 1148 | + /* |
| 1149 | + * NB: Skiboot and pnv_eeh_bridge_reset() also no-op the |
| 1150 | + * de-assert step. It's like the OPAL reset API was |
| 1151 | + * poorly designed or something... |
| 1152 | + */ |
| 1153 | + if (option == EEH_RESET_DEACTIVATE) |
| 1154 | + return 0; |
| 1155 | + |
| 1156 | + rc = pci_bus_error_reset(bus->self); |
| 1157 | + if (!rc) |
| 1158 | + return 0; |
| 1159 | + } |
| 1160 | + |
| 1161 | + /* otherwise, use the generic bridge reset. this might call into FW */ |
| 1162 | + if (pci_is_root_bus(bus->parent)) |
| 1163 | + return pnv_eeh_root_reset(hose, option); |
1132 | 1164 | return pnv_eeh_bridge_reset(bus->self, option);
|
1133 | 1165 | }
|
1134 | 1166 |
|
|
0 commit comments