Commit | Line | Data |
---|---|---|
29310e5e GS |
1 | /* |
2 | * The file intends to implement the platform dependent EEH operations on | |
3 | * powernv platform. Actually, the powernv was created in order to fully | |
4 | * hypervisor support. | |
5 | * | |
6 | * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2013. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | */ | |
13 | ||
14 | #include <linux/atomic.h> | |
15 | #include <linux/delay.h> | |
16 | #include <linux/export.h> | |
17 | #include <linux/init.h> | |
18 | #include <linux/list.h> | |
19 | #include <linux/msi.h> | |
20 | #include <linux/of.h> | |
21 | #include <linux/pci.h> | |
22 | #include <linux/proc_fs.h> | |
23 | #include <linux/rbtree.h> | |
24 | #include <linux/sched.h> | |
25 | #include <linux/seq_file.h> | |
26 | #include <linux/spinlock.h> | |
27 | ||
28 | #include <asm/eeh.h> | |
29 | #include <asm/eeh_event.h> | |
30 | #include <asm/firmware.h> | |
31 | #include <asm/io.h> | |
32 | #include <asm/iommu.h> | |
33 | #include <asm/machdep.h> | |
34 | #include <asm/msi_bitmap.h> | |
35 | #include <asm/opal.h> | |
36 | #include <asm/ppc-pci.h> | |
37 | ||
38 | #include "powernv.h" | |
39 | #include "pci.h" | |
40 | ||
41 | /** | |
42 | * powernv_eeh_init - EEH platform dependent initialization | |
43 | * | |
44 | * EEH platform dependent initialization on powernv | |
45 | */ | |
46 | static int powernv_eeh_init(void) | |
47 | { | |
dc561fb9 GS |
48 | struct pci_controller *hose; |
49 | struct pnv_phb *phb; | |
50 | ||
29310e5e GS |
51 | /* We require OPALv3 */ |
52 | if (!firmware_has_feature(FW_FEATURE_OPALv3)) { | |
0dae2743 GS |
53 | pr_warn("%s: OPALv3 is required !\n", |
54 | __func__); | |
29310e5e GS |
55 | return -EINVAL; |
56 | } | |
57 | ||
05b1721d GS |
58 | /* Set probe mode */ |
59 | eeh_add_flag(EEH_PROBE_MODE_DEV); | |
29310e5e | 60 | |
dc561fb9 GS |
61 | /* |
62 | * P7IOC blocks PCI config access to frozen PE, but PHB3 | |
63 | * doesn't do that. So we have to selectively enable I/O | |
64 | * prior to collecting error log. | |
65 | */ | |
66 | list_for_each_entry(hose, &hose_list, list_node) { | |
67 | phb = hose->private_data; | |
68 | ||
69 | if (phb->model == PNV_PHB_MODEL_P7IOC) | |
70 | eeh_add_flag(EEH_ENABLE_IO_FOR_LOG); | |
71 | break; | |
72 | } | |
73 | ||
29310e5e GS |
74 | return 0; |
75 | } | |
76 | ||
77 | /** | |
78 | * powernv_eeh_post_init - EEH platform dependent post initialization | |
79 | * | |
80 | * EEH platform dependent post initialization on powernv. When | |
81 | * the function is called, the EEH PEs and devices should have | |
82 | * been built. If the I/O cache staff has been built, EEH is | |
83 | * ready to supply service. | |
84 | */ | |
85 | static int powernv_eeh_post_init(void) | |
86 | { | |
87 | struct pci_controller *hose; | |
88 | struct pnv_phb *phb; | |
89 | int ret = 0; | |
90 | ||
91 | list_for_each_entry(hose, &hose_list, list_node) { | |
92 | phb = hose->private_data; | |
93 | ||
94 | if (phb->eeh_ops && phb->eeh_ops->post_init) { | |
95 | ret = phb->eeh_ops->post_init(hose); | |
96 | if (ret) | |
97 | break; | |
98 | } | |
99 | } | |
100 | ||
101 | return ret; | |
102 | } | |
103 | ||
104 | /** | |
105 | * powernv_eeh_dev_probe - Do probe on PCI device | |
106 | * @dev: PCI device | |
107 | * @flag: unused | |
108 | * | |
109 | * When EEH module is installed during system boot, all PCI devices | |
110 | * are checked one by one to see if it supports EEH. The function | |
111 | * is introduced for the purpose. By default, EEH has been enabled | |
112 | * on all PCI devices. That's to say, we only need do necessary | |
113 | * initialization on the corresponding eeh device and create PE | |
114 | * accordingly. | |
115 | * | |
116 | * It's notable that's unsafe to retrieve the EEH device through | |
117 | * the corresponding PCI device. During the PCI device hotplug, which | |
118 | * was possiblly triggered by EEH core, the binding between EEH device | |
119 | * and the PCI device isn't built yet. | |
120 | */ | |
121 | static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) | |
122 | { | |
123 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | |
124 | struct pnv_phb *phb = hose->private_data; | |
125 | struct device_node *dn = pci_device_to_OF_node(dev); | |
126 | struct eeh_dev *edev = of_node_to_eeh_dev(dn); | |
dadcd6d6 | 127 | int ret; |
29310e5e GS |
128 | |
129 | /* | |
130 | * When probing the root bridge, which doesn't have any | |
131 | * subordinate PCI devices. We don't have OF node for | |
132 | * the root bridge. So it's not reasonable to continue | |
133 | * the probing. | |
134 | */ | |
f5c57710 | 135 | if (!dn || !edev || edev->pe) |
29310e5e GS |
136 | return 0; |
137 | ||
138 | /* Skip for PCI-ISA bridge */ | |
139 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_ISA) | |
140 | return 0; | |
141 | ||
142 | /* Initialize eeh device */ | |
ab55d218 GS |
143 | edev->class_code = dev->class; |
144 | edev->mode &= 0xFFFFFF00; | |
4b83bd45 GS |
145 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) |
146 | edev->mode |= EEH_DEV_BRIDGE; | |
2a18dfc6 | 147 | edev->pcix_cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); |
4b83bd45 GS |
148 | if (pci_is_pcie(dev)) { |
149 | edev->pcie_cap = pci_pcie_cap(dev); | |
150 | ||
151 | if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) | |
152 | edev->mode |= EEH_DEV_ROOT_PORT; | |
153 | else if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) | |
154 | edev->mode |= EEH_DEV_DS_PORT; | |
2a18dfc6 GS |
155 | |
156 | edev->aer_cap = pci_find_ext_capability(dev, | |
157 | PCI_EXT_CAP_ID_ERR); | |
4b83bd45 GS |
158 | } |
159 | ||
29310e5e GS |
160 | edev->config_addr = ((dev->bus->number << 8) | dev->devfn); |
161 | edev->pe_config_addr = phb->bdfn_to_pe(phb, dev->bus, dev->devfn & 0xff); | |
162 | ||
163 | /* Create PE */ | |
dadcd6d6 MQ |
164 | ret = eeh_add_to_parent_pe(edev); |
165 | if (ret) { | |
166 | pr_warn("%s: Can't add PCI dev %s to parent PE (%d)\n", | |
167 | __func__, pci_name(dev), ret); | |
168 | return ret; | |
169 | } | |
170 | ||
171 | /* | |
172 | * Cache the PE primary bus, which can't be fetched when | |
173 | * full hotplug is in progress. In that case, all child | |
174 | * PCI devices of the PE are expected to be removed prior | |
175 | * to PE reset. | |
176 | */ | |
177 | if (!edev->pe->bus) | |
178 | edev->pe->bus = dev->bus; | |
29310e5e GS |
179 | |
180 | /* | |
181 | * Enable EEH explicitly so that we will do EEH check | |
182 | * while accessing I/O stuff | |
29310e5e | 183 | */ |
05b1721d | 184 | eeh_add_flag(EEH_ENABLED); |
29310e5e GS |
185 | |
186 | /* Save memory bars */ | |
187 | eeh_save_bars(edev); | |
188 | ||
189 | return 0; | |
190 | } | |
191 | ||
192 | /** | |
193 | * powernv_eeh_set_option - Initialize EEH or MMIO/DMA reenable | |
194 | * @pe: EEH PE | |
195 | * @option: operation to be issued | |
196 | * | |
197 | * The function is used to control the EEH functionality globally. | |
198 | * Currently, following options are support according to PAPR: | |
199 | * Enable EEH, Disable EEH, Enable MMIO and Enable DMA | |
200 | */ | |
201 | static int powernv_eeh_set_option(struct eeh_pe *pe, int option) | |
202 | { | |
203 | struct pci_controller *hose = pe->phb; | |
204 | struct pnv_phb *phb = hose->private_data; | |
205 | int ret = -EEXIST; | |
206 | ||
207 | /* | |
208 | * What we need do is pass it down for hardware | |
209 | * implementation to handle it. | |
210 | */ | |
211 | if (phb->eeh_ops && phb->eeh_ops->set_option) | |
212 | ret = phb->eeh_ops->set_option(pe, option); | |
213 | ||
214 | return ret; | |
215 | } | |
216 | ||
217 | /** | |
218 | * powernv_eeh_get_pe_addr - Retrieve PE address | |
219 | * @pe: EEH PE | |
220 | * | |
221 | * Retrieve the PE address according to the given tranditional | |
222 | * PCI BDF (Bus/Device/Function) address. | |
223 | */ | |
224 | static int powernv_eeh_get_pe_addr(struct eeh_pe *pe) | |
225 | { | |
226 | return pe->addr; | |
227 | } | |
228 | ||
229 | /** | |
230 | * powernv_eeh_get_state - Retrieve PE state | |
231 | * @pe: EEH PE | |
232 | * @delay: delay while PE state is temporarily unavailable | |
233 | * | |
234 | * Retrieve the state of the specified PE. For IODA-compitable | |
235 | * platform, it should be retrieved from IODA table. Therefore, | |
236 | * we prefer passing down to hardware implementation to handle | |
237 | * it. | |
238 | */ | |
239 | static int powernv_eeh_get_state(struct eeh_pe *pe, int *delay) | |
240 | { | |
241 | struct pci_controller *hose = pe->phb; | |
242 | struct pnv_phb *phb = hose->private_data; | |
243 | int ret = EEH_STATE_NOT_SUPPORT; | |
244 | ||
245 | if (phb->eeh_ops && phb->eeh_ops->get_state) { | |
246 | ret = phb->eeh_ops->get_state(pe); | |
247 | ||
248 | /* | |
249 | * If the PE state is temporarily unavailable, | |
250 | * to inform the EEH core delay for default | |
251 | * period (1 second) | |
252 | */ | |
253 | if (delay) { | |
254 | *delay = 0; | |
255 | if (ret & EEH_STATE_UNAVAILABLE) | |
256 | *delay = 1000; | |
257 | } | |
258 | } | |
259 | ||
260 | return ret; | |
261 | } | |
262 | ||
263 | /** | |
264 | * powernv_eeh_reset - Reset the specified PE | |
265 | * @pe: EEH PE | |
266 | * @option: reset option | |
267 | * | |
268 | * Reset the specified PE | |
269 | */ | |
270 | static int powernv_eeh_reset(struct eeh_pe *pe, int option) | |
271 | { | |
272 | struct pci_controller *hose = pe->phb; | |
273 | struct pnv_phb *phb = hose->private_data; | |
274 | int ret = -EEXIST; | |
275 | ||
276 | if (phb->eeh_ops && phb->eeh_ops->reset) | |
277 | ret = phb->eeh_ops->reset(pe, option); | |
278 | ||
279 | return ret; | |
280 | } | |
281 | ||
282 | /** | |
283 | * powernv_eeh_wait_state - Wait for PE state | |
284 | * @pe: EEH PE | |
285 | * @max_wait: maximal period in microsecond | |
286 | * | |
287 | * Wait for the state of associated PE. It might take some time | |
288 | * to retrieve the PE's state. | |
289 | */ | |
290 | static int powernv_eeh_wait_state(struct eeh_pe *pe, int max_wait) | |
291 | { | |
292 | int ret; | |
293 | int mwait; | |
294 | ||
295 | while (1) { | |
296 | ret = powernv_eeh_get_state(pe, &mwait); | |
297 | ||
298 | /* | |
299 | * If the PE's state is temporarily unavailable, | |
300 | * we have to wait for the specified time. Otherwise, | |
301 | * the PE's state will be returned immediately. | |
302 | */ | |
303 | if (ret != EEH_STATE_UNAVAILABLE) | |
304 | return ret; | |
305 | ||
306 | max_wait -= mwait; | |
307 | if (max_wait <= 0) { | |
0dae2743 GS |
308 | pr_warn("%s: Timeout getting PE#%x's state (%d)\n", |
309 | __func__, pe->addr, max_wait); | |
29310e5e GS |
310 | return EEH_STATE_NOT_SUPPORT; |
311 | } | |
312 | ||
313 | msleep(mwait); | |
314 | } | |
315 | ||
316 | return EEH_STATE_NOT_SUPPORT; | |
317 | } | |
318 | ||
319 | /** | |
320 | * powernv_eeh_get_log - Retrieve error log | |
321 | * @pe: EEH PE | |
322 | * @severity: temporary or permanent error log | |
323 | * @drv_log: driver log to be combined with retrieved error log | |
324 | * @len: length of driver log | |
325 | * | |
326 | * Retrieve the temporary or permanent error from the PE. | |
327 | */ | |
328 | static int powernv_eeh_get_log(struct eeh_pe *pe, int severity, | |
bb593c00 | 329 | char *drv_log, unsigned long len) |
29310e5e GS |
330 | { |
331 | struct pci_controller *hose = pe->phb; | |
332 | struct pnv_phb *phb = hose->private_data; | |
333 | int ret = -EEXIST; | |
334 | ||
335 | if (phb->eeh_ops && phb->eeh_ops->get_log) | |
336 | ret = phb->eeh_ops->get_log(pe, severity, drv_log, len); | |
337 | ||
338 | return ret; | |
339 | } | |
340 | ||
341 | /** | |
342 | * powernv_eeh_configure_bridge - Configure PCI bridges in the indicated PE | |
343 | * @pe: EEH PE | |
344 | * | |
345 | * The function will be called to reconfigure the bridges included | |
346 | * in the specified PE so that the mulfunctional PE would be recovered | |
347 | * again. | |
348 | */ | |
349 | static int powernv_eeh_configure_bridge(struct eeh_pe *pe) | |
350 | { | |
351 | struct pci_controller *hose = pe->phb; | |
352 | struct pnv_phb *phb = hose->private_data; | |
353 | int ret = 0; | |
354 | ||
355 | if (phb->eeh_ops && phb->eeh_ops->configure_bridge) | |
356 | ret = phb->eeh_ops->configure_bridge(pe); | |
357 | ||
358 | return ret; | |
359 | } | |
360 | ||
29310e5e GS |
361 | /** |
362 | * powernv_eeh_next_error - Retrieve next EEH error to handle | |
363 | * @pe: Affected PE | |
364 | * | |
365 | * Using OPAL API, to retrieve next EEH error for EEH core to handle | |
366 | */ | |
367 | static int powernv_eeh_next_error(struct eeh_pe **pe) | |
368 | { | |
369 | struct pci_controller *hose; | |
370 | struct pnv_phb *phb = NULL; | |
371 | ||
372 | list_for_each_entry(hose, &hose_list, list_node) { | |
373 | phb = hose->private_data; | |
374 | break; | |
375 | } | |
376 | ||
377 | if (phb && phb->eeh_ops->next_error) | |
378 | return phb->eeh_ops->next_error(pe); | |
379 | ||
380 | return -EEXIST; | |
381 | } | |
382 | ||
9be3becc GS |
383 | static int powernv_eeh_restore_config(struct device_node *dn) |
384 | { | |
385 | struct eeh_dev *edev = of_node_to_eeh_dev(dn); | |
386 | struct pnv_phb *phb; | |
387 | s64 ret; | |
388 | ||
389 | if (!edev) | |
390 | return -EEXIST; | |
391 | ||
392 | phb = edev->phb->private_data; | |
393 | ret = opal_pci_reinit(phb->opal_id, | |
394 | OPAL_REINIT_PCI_DEV, edev->config_addr); | |
395 | if (ret) { | |
396 | pr_warn("%s: Can't reinit PCI dev 0x%x (%lld)\n", | |
397 | __func__, edev->config_addr, ret); | |
398 | return -EIO; | |
399 | } | |
400 | ||
401 | return 0; | |
402 | } | |
403 | ||
29310e5e GS |
404 | static struct eeh_ops powernv_eeh_ops = { |
405 | .name = "powernv", | |
406 | .init = powernv_eeh_init, | |
407 | .post_init = powernv_eeh_post_init, | |
408 | .of_probe = NULL, | |
409 | .dev_probe = powernv_eeh_dev_probe, | |
410 | .set_option = powernv_eeh_set_option, | |
411 | .get_pe_addr = powernv_eeh_get_pe_addr, | |
412 | .get_state = powernv_eeh_get_state, | |
413 | .reset = powernv_eeh_reset, | |
414 | .wait_state = powernv_eeh_wait_state, | |
415 | .get_log = powernv_eeh_get_log, | |
416 | .configure_bridge = powernv_eeh_configure_bridge, | |
9bf41be6 GS |
417 | .read_config = pnv_pci_cfg_read, |
418 | .write_config = pnv_pci_cfg_write, | |
1d350544 | 419 | .next_error = powernv_eeh_next_error, |
9be3becc | 420 | .restore_config = powernv_eeh_restore_config |
29310e5e GS |
421 | }; |
422 | ||
423 | /** | |
424 | * eeh_powernv_init - Register platform dependent EEH operations | |
425 | * | |
426 | * EEH initialization on powernv platform. This function should be | |
427 | * called before any EEH related functions. | |
428 | */ | |
429 | static int __init eeh_powernv_init(void) | |
430 | { | |
431 | int ret = -EINVAL; | |
432 | ||
bb593c00 | 433 | eeh_set_pe_aux_size(PNV_PCI_DIAG_BUF_SIZE); |
29310e5e GS |
434 | ret = eeh_ops_register(&powernv_eeh_ops); |
435 | if (!ret) | |
436 | pr_info("EEH: PowerNV platform initialized\n"); | |
437 | else | |
438 | pr_info("EEH: Failed to initialize PowerNV platform (%d)\n", ret); | |
439 | ||
440 | return ret; | |
441 | } | |
b14726c5 | 442 | machine_early_initcall(powernv, eeh_powernv_init); |