|
34 | 34 | #include "powernv.h"
|
35 | 35 | #include "pci.h"
|
36 | 36 |
|
37 |
| -static s64 ioda_eeh_phb_poll(struct pnv_phb *phb) |
38 |
| -{ |
39 |
| - s64 rc = OPAL_HARDWARE; |
40 |
| - |
41 |
| - while (1) { |
42 |
| - rc = opal_pci_poll(phb->opal_id); |
43 |
| - if (rc <= 0) |
44 |
| - break; |
45 |
| - |
46 |
| - if (system_state < SYSTEM_RUNNING) |
47 |
| - udelay(1000 * rc); |
48 |
| - else |
49 |
| - msleep(rc); |
50 |
| - } |
51 |
| - |
52 |
| - return rc; |
53 |
| -} |
54 |
| - |
55 |
| -int ioda_eeh_phb_reset(struct pci_controller *hose, int option) |
56 |
| -{ |
57 |
| - struct pnv_phb *phb = hose->private_data; |
58 |
| - s64 rc = OPAL_HARDWARE; |
59 |
| - |
60 |
| - pr_debug("%s: Reset PHB#%x, option=%d\n", |
61 |
| - __func__, hose->global_number, option); |
62 |
| - |
63 |
| - /* Issue PHB complete reset request */ |
64 |
| - if (option == EEH_RESET_FUNDAMENTAL || |
65 |
| - option == EEH_RESET_HOT) |
66 |
| - rc = opal_pci_reset(phb->opal_id, |
67 |
| - OPAL_RESET_PHB_COMPLETE, |
68 |
| - OPAL_ASSERT_RESET); |
69 |
| - else if (option == EEH_RESET_DEACTIVATE) |
70 |
| - rc = opal_pci_reset(phb->opal_id, |
71 |
| - OPAL_RESET_PHB_COMPLETE, |
72 |
| - OPAL_DEASSERT_RESET); |
73 |
| - if (rc < 0) |
74 |
| - goto out; |
75 |
| - |
76 |
| - /* |
77 |
| - * Poll state of the PHB until the request is done |
78 |
| - * successfully. The PHB reset is usually PHB complete |
79 |
| - * reset followed by hot reset on root bus. So we also |
80 |
| - * need the PCI bus settlement delay. |
81 |
| - */ |
82 |
| - rc = ioda_eeh_phb_poll(phb); |
83 |
| - if (option == EEH_RESET_DEACTIVATE) { |
84 |
| - if (system_state < SYSTEM_RUNNING) |
85 |
| - udelay(1000 * EEH_PE_RST_SETTLE_TIME); |
86 |
| - else |
87 |
| - msleep(EEH_PE_RST_SETTLE_TIME); |
88 |
| - } |
89 |
| -out: |
90 |
| - if (rc != OPAL_SUCCESS) |
91 |
| - return -EIO; |
92 |
| - |
93 |
| - return 0; |
94 |
| -} |
95 |
| - |
96 |
| -static int ioda_eeh_root_reset(struct pci_controller *hose, int option) |
97 |
| -{ |
98 |
| - struct pnv_phb *phb = hose->private_data; |
99 |
| - s64 rc = OPAL_SUCCESS; |
100 |
| - |
101 |
| - pr_debug("%s: Reset PHB#%x, option=%d\n", |
102 |
| - __func__, hose->global_number, option); |
103 |
| - |
104 |
| - /* |
105 |
| - * During the reset deassert time, we needn't care |
106 |
| - * the reset scope because the firmware does nothing |
107 |
| - * for fundamental or hot reset during deassert phase. |
108 |
| - */ |
109 |
| - if (option == EEH_RESET_FUNDAMENTAL) |
110 |
| - rc = opal_pci_reset(phb->opal_id, |
111 |
| - OPAL_RESET_PCI_FUNDAMENTAL, |
112 |
| - OPAL_ASSERT_RESET); |
113 |
| - else if (option == EEH_RESET_HOT) |
114 |
| - rc = opal_pci_reset(phb->opal_id, |
115 |
| - OPAL_RESET_PCI_HOT, |
116 |
| - OPAL_ASSERT_RESET); |
117 |
| - else if (option == EEH_RESET_DEACTIVATE) |
118 |
| - rc = opal_pci_reset(phb->opal_id, |
119 |
| - OPAL_RESET_PCI_HOT, |
120 |
| - OPAL_DEASSERT_RESET); |
121 |
| - if (rc < 0) |
122 |
| - goto out; |
123 |
| - |
124 |
| - /* Poll state of the PHB until the request is done */ |
125 |
| - rc = ioda_eeh_phb_poll(phb); |
126 |
| - if (option == EEH_RESET_DEACTIVATE) |
127 |
| - msleep(EEH_PE_RST_SETTLE_TIME); |
128 |
| -out: |
129 |
| - if (rc != OPAL_SUCCESS) |
130 |
| - return -EIO; |
131 |
| - |
132 |
| - return 0; |
133 |
| -} |
134 |
| - |
135 |
| -static int ioda_eeh_bridge_reset(struct pci_dev *dev, int option) |
136 |
| - |
137 |
| -{ |
138 |
| - struct device_node *dn = pci_device_to_OF_node(dev); |
139 |
| - struct eeh_dev *edev = of_node_to_eeh_dev(dn); |
140 |
| - int aer = edev ? edev->aer_cap : 0; |
141 |
| - u32 ctrl; |
142 |
| - |
143 |
| - pr_debug("%s: Reset PCI bus %04x:%02x with option %d\n", |
144 |
| - __func__, pci_domain_nr(dev->bus), |
145 |
| - dev->bus->number, option); |
146 |
| - |
147 |
| - switch (option) { |
148 |
| - case EEH_RESET_FUNDAMENTAL: |
149 |
| - case EEH_RESET_HOT: |
150 |
| - /* Don't report linkDown event */ |
151 |
| - if (aer) { |
152 |
| - eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK, |
153 |
| - 4, &ctrl); |
154 |
| - ctrl |= PCI_ERR_UNC_SURPDN; |
155 |
| - eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK, |
156 |
| - 4, ctrl); |
157 |
| - } |
158 |
| - |
159 |
| - eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl); |
160 |
| - ctrl |= PCI_BRIDGE_CTL_BUS_RESET; |
161 |
| - eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl); |
162 |
| - msleep(EEH_PE_RST_HOLD_TIME); |
163 |
| - |
164 |
| - break; |
165 |
| - case EEH_RESET_DEACTIVATE: |
166 |
| - eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl); |
167 |
| - ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; |
168 |
| - eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl); |
169 |
| - msleep(EEH_PE_RST_SETTLE_TIME); |
170 |
| - |
171 |
| - /* Continue reporting linkDown event */ |
172 |
| - if (aer) { |
173 |
| - eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK, |
174 |
| - 4, &ctrl); |
175 |
| - ctrl &= ~PCI_ERR_UNC_SURPDN; |
176 |
| - eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK, |
177 |
| - 4, ctrl); |
178 |
| - } |
179 |
| - |
180 |
| - break; |
181 |
| - } |
182 |
| - |
183 |
| - return 0; |
184 |
| -} |
185 |
| - |
186 |
| -void pnv_pci_reset_secondary_bus(struct pci_dev *dev) |
187 |
| -{ |
188 |
| - struct pci_controller *hose; |
189 |
| - |
190 |
| - if (pci_is_root_bus(dev->bus)) { |
191 |
| - hose = pci_bus_to_host(dev->bus); |
192 |
| - ioda_eeh_root_reset(hose, EEH_RESET_HOT); |
193 |
| - ioda_eeh_root_reset(hose, EEH_RESET_DEACTIVATE); |
194 |
| - } else { |
195 |
| - ioda_eeh_bridge_reset(dev, EEH_RESET_HOT); |
196 |
| - ioda_eeh_bridge_reset(dev, EEH_RESET_DEACTIVATE); |
197 |
| - } |
198 |
| -} |
199 |
| - |
200 |
| -/** |
201 |
| - * ioda_eeh_reset - Reset the indicated PE |
202 |
| - * @pe: EEH PE |
203 |
| - * @option: reset option |
204 |
| - * |
205 |
| - * Do reset on the indicated PE. For PCI bus sensitive PE, |
206 |
| - * we need to reset the parent p2p bridge. The PHB has to |
207 |
| - * be reinitialized if the p2p bridge is root bridge. For |
208 |
| - * PCI device sensitive PE, we will try to reset the device |
209 |
| - * through FLR. For now, we don't have OPAL APIs to do HARD |
210 |
| - * reset yet, so all reset would be SOFT (HOT) reset. |
211 |
| - */ |
212 |
| -static int ioda_eeh_reset(struct eeh_pe *pe, int option) |
213 |
| -{ |
214 |
| - struct pci_controller *hose = pe->phb; |
215 |
| - struct pci_bus *bus; |
216 |
| - int ret; |
217 |
| - |
218 |
| - /* |
219 |
| - * For PHB reset, we always have complete reset. For those PEs whose |
220 |
| - * primary bus derived from root complex (root bus) or root port |
221 |
| - * (usually bus#1), we apply hot or fundamental reset on the root port. |
222 |
| - * For other PEs, we always have hot reset on the PE primary bus. |
223 |
| - * |
224 |
| - * Here, we have different design to pHyp, which always clear the |
225 |
| - * frozen state during PE reset. However, the good idea here from |
226 |
| - * benh is to keep frozen state before we get PE reset done completely |
227 |
| - * (until BAR restore). With the frozen state, HW drops illegal IO |
228 |
| - * or MMIO access, which can incur recrusive frozen PE during PE |
229 |
| - * reset. The side effect is that EEH core has to clear the frozen |
230 |
| - * state explicitly after BAR restore. |
231 |
| - */ |
232 |
| - if (pe->type & EEH_PE_PHB) { |
233 |
| - ret = ioda_eeh_phb_reset(hose, option); |
234 |
| - } else { |
235 |
| - struct pnv_phb *phb; |
236 |
| - s64 rc; |
237 |
| - |
238 |
| - /* |
239 |
| - * The frozen PE might be caused by PAPR error injection |
240 |
| - * registers, which are expected to be cleared after hitting |
241 |
| - * frozen PE as stated in the hardware spec. Unfortunately, |
242 |
| - * that's not true on P7IOC. So we have to clear it manually |
243 |
| - * to avoid recursive EEH errors during recovery. |
244 |
| - */ |
245 |
| - phb = hose->private_data; |
246 |
| - if (phb->model == PNV_PHB_MODEL_P7IOC && |
247 |
| - (option == EEH_RESET_HOT || |
248 |
| - option == EEH_RESET_FUNDAMENTAL)) { |
249 |
| - rc = opal_pci_reset(phb->opal_id, |
250 |
| - OPAL_RESET_PHB_ERROR, |
251 |
| - OPAL_ASSERT_RESET); |
252 |
| - if (rc != OPAL_SUCCESS) { |
253 |
| - pr_warn("%s: Failure %lld clearing " |
254 |
| - "error injection registers\n", |
255 |
| - __func__, rc); |
256 |
| - return -EIO; |
257 |
| - } |
258 |
| - } |
259 |
| - |
260 |
| - bus = eeh_pe_bus_get(pe); |
261 |
| - if (pci_is_root_bus(bus) || |
262 |
| - pci_is_root_bus(bus->parent)) |
263 |
| - ret = ioda_eeh_root_reset(hose, option); |
264 |
| - else |
265 |
| - ret = ioda_eeh_bridge_reset(bus->self, option); |
266 |
| - } |
267 |
| - |
268 |
| - return ret; |
269 |
| -} |
270 |
| - |
271 | 37 | struct pnv_eeh_ops ioda_eeh_ops = {
|
272 |
| - .reset = ioda_eeh_reset, |
273 | 38 | };
|
0 commit comments