Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
aa1e6374 GS |
2 | /* |
3 | * The file intends to implement the platform dependent EEH operations on pseries. | |
4 | * Actually, the pseries platform is built based on RTAS heavily. That means the | |
5 | * pseries platform dependent EEH operations will be built on RTAS calls. The functions | |
027dfac6 | 6 | * are derived from arch/powerpc/platforms/pseries/eeh.c and necessary cleanup has |
aa1e6374 GS |
7 | * been done. |
8 | * | |
9 | * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2011. | |
10 | * Copyright IBM Corporation 2001, 2005, 2006 | |
11 | * Copyright Dave Engebretsen & Todd Inglett 2001 | |
12 | * Copyright Linas Vepstas 2005, 2006 | |
aa1e6374 GS |
13 | */ |
14 | ||
15 | #include <linux/atomic.h> | |
16 | #include <linux/delay.h> | |
17 | #include <linux/export.h> | |
18 | #include <linux/init.h> | |
19 | #include <linux/list.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/io.h> | |
31 | #include <asm/machdep.h> | |
32 | #include <asm/ppc-pci.h> | |
33 | #include <asm/rtas.h> | |
34 | ||
e2af155c GS |
35 | /* RTAS tokens */ |
36 | static int ibm_set_eeh_option; | |
37 | static int ibm_set_slot_reset; | |
38 | static int ibm_read_slot_reset_state; | |
39 | static int ibm_read_slot_reset_state2; | |
40 | static int ibm_slot_error_detail; | |
41 | static int ibm_get_config_addr_info; | |
42 | static int ibm_get_config_addr_info2; | |
e2af155c GS |
43 | static int ibm_configure_pe; |
44 | ||
565a744d | 45 | #ifdef CONFIG_PCI_IOV |
dae7253f BL |
46 | void pseries_pcibios_bus_add_device(struct pci_dev *pdev) |
47 | { | |
48 | struct pci_dn *pdn = pci_get_pdn(pdev); | |
565a744d BL |
49 | struct pci_dn *physfn_pdn; |
50 | struct eeh_dev *edev; | |
dae7253f BL |
51 | |
52 | if (!pdev->is_virtfn) | |
53 | return; | |
54 | ||
55 | pdn->device_id = pdev->device; | |
56 | pdn->vendor_id = pdev->vendor; | |
57 | pdn->class_code = pdev->class; | |
565a744d BL |
58 | /* |
59 | * Last allow unfreeze return code used for retrieval | |
60 | * by user space in eeh-sysfs to show the last command | |
61 | * completion from platform. | |
62 | */ | |
63 | pdn->last_allow_rc = 0; | |
64 | physfn_pdn = pci_get_pdn(pdev->physfn); | |
65 | pdn->pe_number = physfn_pdn->pe_num_map[pdn->vf_index]; | |
66 | edev = pdn_to_eeh_dev(pdn); | |
dae7253f BL |
67 | |
68 | /* | |
69 | * The following operations will fail if VF's sysfs files | |
70 | * aren't created or its resources aren't finalized. | |
71 | */ | |
72 | eeh_add_device_early(pdn); | |
73 | eeh_add_device_late(pdev); | |
565a744d BL |
74 | edev->pe_config_addr = (pdn->busno << 16) | (pdn->devfn << 8); |
75 | eeh_rmv_from_parent_pe(edev); /* Remove as it is adding to bus pe */ | |
76 | eeh_add_to_parent_pe(edev); /* Add as VF PE type */ | |
dae7253f BL |
77 | eeh_sysfs_add_device(pdev); |
78 | ||
79 | } | |
565a744d | 80 | #endif |
dae7253f | 81 | |
8d633291 GS |
82 | /* |
83 | * Buffer for reporting slot-error-detail rtas calls. Its here | |
84 | * in BSS, and not dynamically alloced, so that it ends up in | |
85 | * RMO where RTAS can access it. | |
86 | */ | |
87 | static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; | |
88 | static DEFINE_SPINLOCK(slot_errbuf_lock); | |
89 | static int eeh_error_buf_size; | |
90 | ||
aa1e6374 GS |
91 | /** |
92 | * pseries_eeh_init - EEH platform dependent initialization | |
93 | * | |
94 | * EEH platform dependent initialization on pseries. | |
95 | */ | |
96 | static int pseries_eeh_init(void) | |
97 | { | |
e2af155c GS |
98 | /* figure out EEH RTAS function call tokens */ |
99 | ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); | |
100 | ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); | |
101 | ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); | |
102 | ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); | |
103 | ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); | |
104 | ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); | |
105 | ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); | |
106 | ibm_configure_pe = rtas_token("ibm,configure-pe"); | |
bd000b82 RC |
107 | |
108 | /* | |
109 | * ibm,configure-pe and ibm,configure-bridge have the same semantics, | |
110 | * however ibm,configure-pe can be faster. If we can't find | |
111 | * ibm,configure-pe then fall back to using ibm,configure-bridge. | |
112 | */ | |
113 | if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE) | |
114 | ibm_configure_pe = rtas_token("ibm,configure-bridge"); | |
e2af155c | 115 | |
b8b3de22 GS |
116 | /* |
117 | * Necessary sanity check. We needn't check "get-config-addr-info" | |
118 | * and its variant since the old firmware probably support address | |
119 | * of domain/bus/slot/function for EEH RTAS operations. | |
120 | */ | |
4ba5a0fc GS |
121 | if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE || |
122 | ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE || | |
123 | (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE && | |
124 | ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) || | |
125 | ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE || | |
bd000b82 | 126 | ibm_configure_pe == RTAS_UNKNOWN_SERVICE) { |
4ba5a0fc | 127 | pr_info("EEH functionality not supported\n"); |
e2af155c GS |
128 | return -EINVAL; |
129 | } | |
130 | ||
8d633291 GS |
131 | /* Initialize error log lock and size */ |
132 | spin_lock_init(&slot_errbuf_lock); | |
133 | eeh_error_buf_size = rtas_token("rtas-error-log-max"); | |
134 | if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { | |
4ba5a0fc | 135 | pr_info("%s: unknown EEH error log size\n", |
8d633291 GS |
136 | __func__); |
137 | eeh_error_buf_size = 1024; | |
138 | } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { | |
4ba5a0fc | 139 | pr_info("%s: EEH error log size %d exceeds the maximal %d\n", |
8d633291 GS |
140 | __func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX); |
141 | eeh_error_buf_size = RTAS_ERROR_LOG_MAX; | |
142 | } | |
143 | ||
d7bb8862 | 144 | /* Set EEH probe mode */ |
dc561fb9 | 145 | eeh_add_flag(EEH_PROBE_MODE_DEVTREE | EEH_ENABLE_IO_FOR_LOG); |
d7bb8862 | 146 | |
565a744d | 147 | #ifdef CONFIG_PCI_IOV |
dae7253f BL |
148 | /* Set EEH machine dependent code */ |
149 | ppc_md.pcibios_bus_add_device = pseries_pcibios_bus_add_device; | |
565a744d | 150 | #endif |
dae7253f | 151 | |
aa1e6374 GS |
152 | return 0; |
153 | } | |
154 | ||
ff57b454 | 155 | static int pseries_eeh_cap_start(struct pci_dn *pdn) |
4b83bd45 | 156 | { |
4b83bd45 GS |
157 | u32 status; |
158 | ||
159 | if (!pdn) | |
160 | return 0; | |
161 | ||
162 | rtas_read_config(pdn, PCI_STATUS, 2, &status); | |
163 | if (!(status & PCI_STATUS_CAP_LIST)) | |
164 | return 0; | |
165 | ||
166 | return PCI_CAPABILITY_LIST; | |
167 | } | |
168 | ||
169 | ||
ff57b454 | 170 | static int pseries_eeh_find_cap(struct pci_dn *pdn, int cap) |
4b83bd45 | 171 | { |
ff57b454 | 172 | int pos = pseries_eeh_cap_start(pdn); |
4b83bd45 GS |
173 | int cnt = 48; /* Maximal number of capabilities */ |
174 | u32 id; | |
175 | ||
176 | if (!pos) | |
177 | return 0; | |
178 | ||
179 | while (cnt--) { | |
180 | rtas_read_config(pdn, pos, 1, &pos); | |
181 | if (pos < 0x40) | |
182 | break; | |
183 | pos &= ~3; | |
184 | rtas_read_config(pdn, pos + PCI_CAP_LIST_ID, 1, &id); | |
185 | if (id == 0xff) | |
186 | break; | |
187 | if (id == cap) | |
188 | return pos; | |
189 | pos += PCI_CAP_LIST_NEXT; | |
190 | } | |
191 | ||
192 | return 0; | |
193 | } | |
194 | ||
ff57b454 | 195 | static int pseries_eeh_find_ecap(struct pci_dn *pdn, int cap) |
2a18dfc6 | 196 | { |
ff57b454 | 197 | struct eeh_dev *edev = pdn_to_eeh_dev(pdn); |
2a18dfc6 GS |
198 | u32 header; |
199 | int pos = 256; | |
200 | int ttl = (4096 - 256) / 8; | |
201 | ||
202 | if (!edev || !edev->pcie_cap) | |
203 | return 0; | |
204 | if (rtas_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL) | |
205 | return 0; | |
206 | else if (!header) | |
207 | return 0; | |
208 | ||
209 | while (ttl-- > 0) { | |
210 | if (PCI_EXT_CAP_ID(header) == cap && pos) | |
211 | return pos; | |
212 | ||
213 | pos = PCI_EXT_CAP_NEXT(header); | |
214 | if (pos < 256) | |
215 | break; | |
216 | ||
217 | if (rtas_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL) | |
218 | break; | |
219 | } | |
220 | ||
221 | return 0; | |
222 | } | |
223 | ||
d7bb8862 | 224 | /** |
ff57b454 GS |
225 | * pseries_eeh_probe - EEH probe on the given device |
226 | * @pdn: PCI device node | |
227 | * @data: Unused | |
d7bb8862 GS |
228 | * |
229 | * When EEH module is installed during system boot, all PCI devices | |
230 | * are checked one by one to see if it supports EEH. The function | |
231 | * is introduced for the purpose. | |
232 | */ | |
ff57b454 | 233 | static void *pseries_eeh_probe(struct pci_dn *pdn, void *data) |
d7bb8862 GS |
234 | { |
235 | struct eeh_dev *edev; | |
236 | struct eeh_pe pe; | |
4b83bd45 | 237 | u32 pcie_flags; |
d7bb8862 GS |
238 | int enable = 0; |
239 | int ret; | |
240 | ||
241 | /* Retrieve OF node and eeh device */ | |
ff57b454 GS |
242 | edev = pdn_to_eeh_dev(pdn); |
243 | if (!edev || edev->pe) | |
d7bb8862 GS |
244 | return NULL; |
245 | ||
ff57b454 GS |
246 | /* Check class/vendor/device IDs */ |
247 | if (!pdn->vendor_id || !pdn->device_id || !pdn->class_code) | |
d7bb8862 GS |
248 | return NULL; |
249 | ||
ff57b454 GS |
250 | /* Skip for PCI-ISA bridge */ |
251 | if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA) | |
252 | return NULL; | |
b91da2d4 | 253 | |
4b83bd45 GS |
254 | /* |
255 | * Update class code and mode of eeh device. We need | |
256 | * correctly reflects that current device is root port | |
257 | * or PCIe switch downstream port. | |
258 | */ | |
ff57b454 GS |
259 | edev->class_code = pdn->class_code; |
260 | edev->pcix_cap = pseries_eeh_find_cap(pdn, PCI_CAP_ID_PCIX); | |
261 | edev->pcie_cap = pseries_eeh_find_cap(pdn, PCI_CAP_ID_EXP); | |
262 | edev->aer_cap = pseries_eeh_find_ecap(pdn, PCI_EXT_CAP_ID_ERR); | |
ab55d218 | 263 | edev->mode &= 0xFFFFFF00; |
4b83bd45 GS |
264 | if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) { |
265 | edev->mode |= EEH_DEV_BRIDGE; | |
266 | if (edev->pcie_cap) { | |
267 | rtas_read_config(pdn, edev->pcie_cap + PCI_EXP_FLAGS, | |
268 | 2, &pcie_flags); | |
269 | pcie_flags = (pcie_flags & PCI_EXP_FLAGS_TYPE) >> 4; | |
270 | if (pcie_flags == PCI_EXP_TYPE_ROOT_PORT) | |
271 | edev->mode |= EEH_DEV_ROOT_PORT; | |
272 | else if (pcie_flags == PCI_EXP_TYPE_DOWNSTREAM) | |
273 | edev->mode |= EEH_DEV_DS_PORT; | |
274 | } | |
275 | } | |
d7bb8862 | 276 | |
d7bb8862 GS |
277 | /* Initialize the fake PE */ |
278 | memset(&pe, 0, sizeof(struct eeh_pe)); | |
69672bd7 | 279 | pe.phb = pdn->phb; |
ff57b454 | 280 | pe.config_addr = (pdn->busno << 16) | (pdn->devfn << 8); |
d7bb8862 GS |
281 | |
282 | /* Enable EEH on the device */ | |
283 | ret = eeh_ops->set_option(&pe, EEH_OPT_ENABLE); | |
284 | if (!ret) { | |
d7bb8862 GS |
285 | /* Retrieve PE address */ |
286 | edev->pe_config_addr = eeh_ops->get_pe_addr(&pe); | |
287 | pe.addr = edev->pe_config_addr; | |
288 | ||
289 | /* Some older systems (Power4) allow the ibm,set-eeh-option | |
290 | * call to succeed even on nodes where EEH is not supported. | |
291 | * Verify support explicitly. | |
292 | */ | |
293 | ret = eeh_ops->get_state(&pe, NULL); | |
294 | if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT) | |
295 | enable = 1; | |
296 | ||
297 | if (enable) { | |
05b1721d | 298 | eeh_add_flag(EEH_ENABLED); |
d7bb8862 GS |
299 | eeh_add_to_parent_pe(edev); |
300 | ||
1f52f176 | 301 | pr_debug("%s: EEH enabled on %02x:%02x.%01x PHB#%x-PE#%x\n", |
ff57b454 GS |
302 | __func__, pdn->busno, PCI_SLOT(pdn->devfn), |
303 | PCI_FUNC(pdn->devfn), pe.phb->global_number, | |
304 | pe.addr); | |
305 | } else if (pdn->parent && pdn_to_eeh_dev(pdn->parent) && | |
306 | (pdn_to_eeh_dev(pdn->parent))->pe) { | |
d7bb8862 GS |
307 | /* This device doesn't support EEH, but it may have an |
308 | * EEH parent, in which case we mark it as supported. | |
309 | */ | |
ff57b454 | 310 | edev->pe_config_addr = pdn_to_eeh_dev(pdn->parent)->pe_config_addr; |
d7bb8862 GS |
311 | eeh_add_to_parent_pe(edev); |
312 | } | |
313 | } | |
314 | ||
315 | /* Save memory bars */ | |
316 | eeh_save_bars(edev); | |
317 | ||
318 | return NULL; | |
319 | } | |
320 | ||
aa1e6374 GS |
321 | /** |
322 | * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable | |
371a395d | 323 | * @pe: EEH PE |
aa1e6374 GS |
324 | * @option: operation to be issued |
325 | * | |
326 | * The function is used to control the EEH functionality globally. | |
327 | * Currently, following options are support according to PAPR: | |
328 | * Enable EEH, Disable EEH, Enable MMIO and Enable DMA | |
329 | */ | |
371a395d | 330 | static int pseries_eeh_set_option(struct eeh_pe *pe, int option) |
aa1e6374 | 331 | { |
8fb8f709 | 332 | int ret = 0; |
8fb8f709 GS |
333 | int config_addr; |
334 | ||
8fb8f709 GS |
335 | /* |
336 | * When we're enabling or disabling EEH functioality on | |
337 | * the particular PE, the PE config address is possibly | |
338 | * unavailable. Therefore, we have to figure it out from | |
339 | * the FDT node. | |
340 | */ | |
341 | switch (option) { | |
342 | case EEH_OPT_DISABLE: | |
343 | case EEH_OPT_ENABLE: | |
8fb8f709 GS |
344 | case EEH_OPT_THAW_MMIO: |
345 | case EEH_OPT_THAW_DMA: | |
371a395d GS |
346 | config_addr = pe->config_addr; |
347 | if (pe->addr) | |
348 | config_addr = pe->addr; | |
8fb8f709 | 349 | break; |
0d5ee520 GS |
350 | case EEH_OPT_FREEZE_PE: |
351 | /* Not support */ | |
352 | return 0; | |
8fb8f709 GS |
353 | default: |
354 | pr_err("%s: Invalid option %d\n", | |
355 | __func__, option); | |
356 | return -EINVAL; | |
357 | } | |
358 | ||
359 | ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, | |
371a395d GS |
360 | config_addr, BUID_HI(pe->phb->buid), |
361 | BUID_LO(pe->phb->buid), option); | |
8fb8f709 GS |
362 | |
363 | return ret; | |
aa1e6374 GS |
364 | } |
365 | ||
366 | /** | |
367 | * pseries_eeh_get_pe_addr - Retrieve PE address | |
371a395d | 368 | * @pe: EEH PE |
aa1e6374 GS |
369 | * |
370 | * Retrieve the assocated PE address. Actually, there're 2 RTAS | |
371 | * function calls dedicated for the purpose. We need implement | |
372 | * it through the new function and then the old one. Besides, | |
373 | * you should make sure the config address is figured out from | |
374 | * FDT node before calling the function. | |
375 | * | |
376 | * It's notable that zero'ed return value means invalid PE config | |
377 | * address. | |
378 | */ | |
371a395d | 379 | static int pseries_eeh_get_pe_addr(struct eeh_pe *pe) |
aa1e6374 | 380 | { |
c8c29b38 GS |
381 | int ret = 0; |
382 | int rets[3]; | |
383 | ||
c8c29b38 GS |
384 | if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { |
385 | /* | |
386 | * First of all, we need to make sure there has one PE | |
387 | * associated with the device. Otherwise, PE address is | |
388 | * meaningless. | |
389 | */ | |
390 | ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, | |
371a395d GS |
391 | pe->config_addr, BUID_HI(pe->phb->buid), |
392 | BUID_LO(pe->phb->buid), 1); | |
c8c29b38 GS |
393 | if (ret || (rets[0] == 0)) |
394 | return 0; | |
395 | ||
396 | /* Retrieve the associated PE config address */ | |
397 | ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, | |
371a395d GS |
398 | pe->config_addr, BUID_HI(pe->phb->buid), |
399 | BUID_LO(pe->phb->buid), 0); | |
c8c29b38 | 400 | if (ret) { |
1f52f176 | 401 | pr_warn("%s: Failed to get address for PHB#%x-PE#%x\n", |
371a395d | 402 | __func__, pe->phb->global_number, pe->config_addr); |
c8c29b38 GS |
403 | return 0; |
404 | } | |
405 | ||
406 | return rets[0]; | |
407 | } | |
408 | ||
409 | if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { | |
410 | ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets, | |
371a395d GS |
411 | pe->config_addr, BUID_HI(pe->phb->buid), |
412 | BUID_LO(pe->phb->buid), 0); | |
c8c29b38 | 413 | if (ret) { |
1f52f176 | 414 | pr_warn("%s: Failed to get address for PHB#%x-PE#%x\n", |
371a395d | 415 | __func__, pe->phb->global_number, pe->config_addr); |
c8c29b38 GS |
416 | return 0; |
417 | } | |
418 | ||
419 | return rets[0]; | |
420 | } | |
421 | ||
422 | return ret; | |
aa1e6374 GS |
423 | } |
424 | ||
425 | /** | |
426 | * pseries_eeh_get_state - Retrieve PE state | |
371a395d | 427 | * @pe: EEH PE |
fef7f905 | 428 | * @delay: suggested time to wait if state is unavailable |
aa1e6374 GS |
429 | * |
430 | * Retrieve the state of the specified PE. On RTAS compliant | |
431 | * pseries platform, there already has one dedicated RTAS function | |
432 | * for the purpose. It's notable that the associated PE config address | |
433 | * might be ready when calling the function. Therefore, endeavour to | |
434 | * use the PE config address if possible. Further more, there're 2 | |
435 | * RTAS calls for the purpose, we need to try the new one and back | |
436 | * to the old one if the new one couldn't work properly. | |
437 | */ | |
fef7f905 | 438 | static int pseries_eeh_get_state(struct eeh_pe *pe, int *delay) |
aa1e6374 | 439 | { |
eb594a47 GS |
440 | int config_addr; |
441 | int ret; | |
442 | int rets[4]; | |
443 | int result; | |
444 | ||
445 | /* Figure out PE config address if possible */ | |
371a395d GS |
446 | config_addr = pe->config_addr; |
447 | if (pe->addr) | |
448 | config_addr = pe->addr; | |
eb594a47 GS |
449 | |
450 | if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { | |
451 | ret = rtas_call(ibm_read_slot_reset_state2, 3, 4, rets, | |
371a395d GS |
452 | config_addr, BUID_HI(pe->phb->buid), |
453 | BUID_LO(pe->phb->buid)); | |
eb594a47 GS |
454 | } else if (ibm_read_slot_reset_state != RTAS_UNKNOWN_SERVICE) { |
455 | /* Fake PE unavailable info */ | |
456 | rets[2] = 0; | |
457 | ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, | |
371a395d GS |
458 | config_addr, BUID_HI(pe->phb->buid), |
459 | BUID_LO(pe->phb->buid)); | |
eb594a47 GS |
460 | } else { |
461 | return EEH_STATE_NOT_SUPPORT; | |
462 | } | |
463 | ||
464 | if (ret) | |
465 | return ret; | |
466 | ||
467 | /* Parse the result out */ | |
00ba05a1 GS |
468 | if (!rets[1]) |
469 | return EEH_STATE_NOT_SUPPORT; | |
470 | ||
471 | switch(rets[0]) { | |
472 | case 0: | |
473 | result = EEH_STATE_MMIO_ACTIVE | | |
474 | EEH_STATE_DMA_ACTIVE; | |
475 | break; | |
476 | case 1: | |
477 | result = EEH_STATE_RESET_ACTIVE | | |
478 | EEH_STATE_MMIO_ACTIVE | | |
479 | EEH_STATE_DMA_ACTIVE; | |
480 | break; | |
481 | case 2: | |
482 | result = 0; | |
483 | break; | |
484 | case 4: | |
485 | result = EEH_STATE_MMIO_ENABLED; | |
486 | break; | |
487 | case 5: | |
488 | if (rets[2]) { | |
fef7f905 SB |
489 | if (delay) |
490 | *delay = rets[2]; | |
00ba05a1 GS |
491 | result = EEH_STATE_UNAVAILABLE; |
492 | } else { | |
eb594a47 GS |
493 | result = EEH_STATE_NOT_SUPPORT; |
494 | } | |
00ba05a1 GS |
495 | break; |
496 | default: | |
eb594a47 GS |
497 | result = EEH_STATE_NOT_SUPPORT; |
498 | } | |
499 | ||
500 | return result; | |
aa1e6374 GS |
501 | } |
502 | ||
503 | /** | |
504 | * pseries_eeh_reset - Reset the specified PE | |
371a395d | 505 | * @pe: EEH PE |
aa1e6374 GS |
506 | * @option: reset option |
507 | * | |
508 | * Reset the specified PE | |
509 | */ | |
371a395d | 510 | static int pseries_eeh_reset(struct eeh_pe *pe, int option) |
aa1e6374 | 511 | { |
2652481f GS |
512 | int config_addr; |
513 | int ret; | |
514 | ||
515 | /* Figure out PE address */ | |
371a395d GS |
516 | config_addr = pe->config_addr; |
517 | if (pe->addr) | |
518 | config_addr = pe->addr; | |
2652481f GS |
519 | |
520 | /* Reset PE through RTAS call */ | |
521 | ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, | |
371a395d GS |
522 | config_addr, BUID_HI(pe->phb->buid), |
523 | BUID_LO(pe->phb->buid), option); | |
2652481f GS |
524 | |
525 | /* If fundamental-reset not supported, try hot-reset */ | |
526 | if (option == EEH_RESET_FUNDAMENTAL && | |
527 | ret == -8) { | |
26833a50 | 528 | option = EEH_RESET_HOT; |
2652481f | 529 | ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, |
371a395d | 530 | config_addr, BUID_HI(pe->phb->buid), |
26833a50 | 531 | BUID_LO(pe->phb->buid), option); |
2652481f GS |
532 | } |
533 | ||
26833a50 GS |
534 | /* We need reset hold or settlement delay */ |
535 | if (option == EEH_RESET_FUNDAMENTAL || | |
536 | option == EEH_RESET_HOT) | |
537 | msleep(EEH_PE_RST_HOLD_TIME); | |
538 | else | |
539 | msleep(EEH_PE_RST_SETTLE_TIME); | |
540 | ||
2652481f | 541 | return ret; |
aa1e6374 GS |
542 | } |
543 | ||
aa1e6374 GS |
544 | /** |
545 | * pseries_eeh_get_log - Retrieve error log | |
371a395d | 546 | * @pe: EEH PE |
aa1e6374 GS |
547 | * @severity: temporary or permanent error log |
548 | * @drv_log: driver log to be combined with retrieved error log | |
549 | * @len: length of driver log | |
550 | * | |
551 | * Retrieve the temporary or permanent error from the PE. | |
552 | * Actually, the error will be retrieved through the dedicated | |
553 | * RTAS call. | |
554 | */ | |
371a395d | 555 | static int pseries_eeh_get_log(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len) |
aa1e6374 | 556 | { |
8d633291 GS |
557 | int config_addr; |
558 | unsigned long flags; | |
559 | int ret; | |
560 | ||
8d633291 GS |
561 | spin_lock_irqsave(&slot_errbuf_lock, flags); |
562 | memset(slot_errbuf, 0, eeh_error_buf_size); | |
563 | ||
564 | /* Figure out the PE address */ | |
371a395d GS |
565 | config_addr = pe->config_addr; |
566 | if (pe->addr) | |
567 | config_addr = pe->addr; | |
8d633291 GS |
568 | |
569 | ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr, | |
371a395d | 570 | BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid), |
8d633291 GS |
571 | virt_to_phys(drv_log), len, |
572 | virt_to_phys(slot_errbuf), eeh_error_buf_size, | |
573 | severity); | |
574 | if (!ret) | |
575 | log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); | |
576 | spin_unlock_irqrestore(&slot_errbuf_lock, flags); | |
577 | ||
578 | return ret; | |
aa1e6374 GS |
579 | } |
580 | ||
581 | /** | |
582 | * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE | |
371a395d | 583 | * @pe: EEH PE |
aa1e6374 GS |
584 | * |
585 | * The function will be called to reconfigure the bridges included | |
586 | * in the specified PE so that the mulfunctional PE would be recovered | |
587 | * again. | |
588 | */ | |
371a395d | 589 | static int pseries_eeh_configure_bridge(struct eeh_pe *pe) |
aa1e6374 | 590 | { |
1823fbf1 GS |
591 | int config_addr; |
592 | int ret; | |
871e178e RC |
593 | /* Waiting 0.2s maximum before skipping configuration */ |
594 | int max_wait = 200; | |
1823fbf1 GS |
595 | |
596 | /* Figure out the PE address */ | |
371a395d GS |
597 | config_addr = pe->config_addr; |
598 | if (pe->addr) | |
599 | config_addr = pe->addr; | |
1823fbf1 | 600 | |
871e178e | 601 | while (max_wait > 0) { |
bd000b82 RC |
602 | ret = rtas_call(ibm_configure_pe, 3, 1, NULL, |
603 | config_addr, BUID_HI(pe->phb->buid), | |
604 | BUID_LO(pe->phb->buid)); | |
1823fbf1 | 605 | |
871e178e RC |
606 | if (!ret) |
607 | return ret; | |
608 | ||
609 | /* | |
610 | * If RTAS returns a delay value that's above 100ms, cut it | |
611 | * down to 100ms in case firmware made a mistake. For more | |
612 | * on how these delay values work see rtas_busy_delay_time | |
613 | */ | |
614 | if (ret > RTAS_EXTENDED_DELAY_MIN+2 && | |
615 | ret <= RTAS_EXTENDED_DELAY_MAX) | |
616 | ret = RTAS_EXTENDED_DELAY_MIN+2; | |
617 | ||
618 | max_wait -= rtas_busy_delay_time(ret); | |
619 | ||
620 | if (max_wait < 0) | |
621 | break; | |
622 | ||
623 | rtas_busy_delay(ret); | |
624 | } | |
1823fbf1 | 625 | |
1f52f176 | 626 | pr_warn("%s: Unable to configure bridge PHB#%x-PE#%x (%d)\n", |
871e178e | 627 | __func__, pe->phb->global_number, pe->addr, ret); |
1823fbf1 | 628 | return ret; |
aa1e6374 GS |
629 | } |
630 | ||
3780444c GS |
631 | /** |
632 | * pseries_eeh_read_config - Read PCI config space | |
0bd78587 | 633 | * @pdn: PCI device node |
3780444c GS |
634 | * @where: PCI address |
635 | * @size: size to read | |
636 | * @val: return value | |
637 | * | |
638 | * Read config space from the speicifed device | |
639 | */ | |
0bd78587 | 640 | static int pseries_eeh_read_config(struct pci_dn *pdn, int where, int size, u32 *val) |
3780444c | 641 | { |
3780444c GS |
642 | return rtas_read_config(pdn, where, size, val); |
643 | } | |
644 | ||
645 | /** | |
646 | * pseries_eeh_write_config - Write PCI config space | |
0bd78587 | 647 | * @pdn: PCI device node |
3780444c GS |
648 | * @where: PCI address |
649 | * @size: size to write | |
650 | * @val: value to be written | |
651 | * | |
652 | * Write config space to the specified device | |
653 | */ | |
0bd78587 | 654 | static int pseries_eeh_write_config(struct pci_dn *pdn, int where, int size, u32 val) |
3780444c | 655 | { |
3780444c GS |
656 | return rtas_write_config(pdn, where, size, val); |
657 | } | |
658 | ||
64ba3dc7 BL |
659 | static int pseries_eeh_restore_config(struct pci_dn *pdn) |
660 | { | |
661 | struct eeh_dev *edev = pdn_to_eeh_dev(pdn); | |
662 | s64 ret = 0; | |
663 | ||
664 | if (!edev) | |
665 | return -EEXIST; | |
666 | ||
667 | /* | |
668 | * FIXME: The MPS, error routing rules, timeout setting are worthy | |
669 | * to be exported by firmware in extendible way. | |
670 | */ | |
671 | if (edev->physfn) | |
672 | ret = eeh_restore_vf_config(pdn); | |
673 | ||
674 | if (ret) { | |
675 | pr_warn("%s: Can't reinit PCI dev 0x%x (%lld)\n", | |
676 | __func__, edev->pe_config_addr, ret); | |
677 | return -EIO; | |
678 | } | |
679 | ||
680 | return ret; | |
681 | } | |
682 | ||
67923cfc BL |
683 | #ifdef CONFIG_PCI_IOV |
684 | int pseries_send_allow_unfreeze(struct pci_dn *pdn, | |
685 | u16 *vf_pe_array, int cur_vfs) | |
686 | { | |
687 | int rc; | |
688 | int ibm_allow_unfreeze = rtas_token("ibm,open-sriov-allow-unfreeze"); | |
689 | unsigned long buid, addr; | |
690 | ||
691 | addr = rtas_config_addr(pdn->busno, pdn->devfn, 0); | |
692 | buid = pdn->phb->buid; | |
693 | spin_lock(&rtas_data_buf_lock); | |
694 | memcpy(rtas_data_buf, vf_pe_array, RTAS_DATA_BUF_SIZE); | |
695 | rc = rtas_call(ibm_allow_unfreeze, 5, 1, NULL, | |
696 | addr, | |
697 | BUID_HI(buid), | |
698 | BUID_LO(buid), | |
699 | rtas_data_buf, cur_vfs * sizeof(u16)); | |
700 | spin_unlock(&rtas_data_buf_lock); | |
701 | if (rc) | |
702 | pr_warn("%s: Failed to allow unfreeze for PHB#%x-PE#%lx, rc=%x\n", | |
703 | __func__, | |
704 | pdn->phb->global_number, addr, rc); | |
705 | return rc; | |
706 | } | |
707 | ||
708 | static int pseries_call_allow_unfreeze(struct eeh_dev *edev) | |
709 | { | |
710 | struct pci_dn *pdn, *tmp, *parent, *physfn_pdn; | |
711 | int cur_vfs = 0, rc = 0, vf_index, bus, devfn; | |
712 | u16 *vf_pe_array; | |
713 | ||
714 | vf_pe_array = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); | |
715 | if (!vf_pe_array) | |
716 | return -ENOMEM; | |
717 | if (pci_num_vf(edev->physfn ? edev->physfn : edev->pdev)) { | |
718 | if (edev->pdev->is_physfn) { | |
719 | cur_vfs = pci_num_vf(edev->pdev); | |
720 | pdn = eeh_dev_to_pdn(edev); | |
721 | parent = pdn->parent; | |
722 | for (vf_index = 0; vf_index < cur_vfs; vf_index++) | |
723 | vf_pe_array[vf_index] = | |
724 | cpu_to_be16(pdn->pe_num_map[vf_index]); | |
725 | rc = pseries_send_allow_unfreeze(pdn, vf_pe_array, | |
726 | cur_vfs); | |
727 | pdn->last_allow_rc = rc; | |
728 | for (vf_index = 0; vf_index < cur_vfs; vf_index++) { | |
729 | list_for_each_entry_safe(pdn, tmp, | |
730 | &parent->child_list, | |
731 | list) { | |
732 | bus = pci_iov_virtfn_bus(edev->pdev, | |
733 | vf_index); | |
734 | devfn = pci_iov_virtfn_devfn(edev->pdev, | |
735 | vf_index); | |
736 | if (pdn->busno != bus || | |
737 | pdn->devfn != devfn) | |
738 | continue; | |
739 | pdn->last_allow_rc = rc; | |
740 | } | |
741 | } | |
742 | } else { | |
743 | pdn = pci_get_pdn(edev->pdev); | |
744 | vf_pe_array[0] = cpu_to_be16(pdn->pe_number); | |
745 | physfn_pdn = pci_get_pdn(edev->physfn); | |
746 | rc = pseries_send_allow_unfreeze(physfn_pdn, | |
747 | vf_pe_array, 1); | |
748 | pdn->last_allow_rc = rc; | |
749 | } | |
750 | } | |
751 | ||
752 | kfree(vf_pe_array); | |
753 | return rc; | |
754 | } | |
755 | ||
756 | static int pseries_notify_resume(struct pci_dn *pdn) | |
757 | { | |
758 | struct eeh_dev *edev = pdn_to_eeh_dev(pdn); | |
759 | ||
760 | if (!edev) | |
761 | return -EEXIST; | |
762 | ||
763 | if (rtas_token("ibm,open-sriov-allow-unfreeze") | |
764 | == RTAS_UNKNOWN_SERVICE) | |
765 | return -EINVAL; | |
766 | ||
767 | if (edev->pdev->is_physfn || edev->pdev->is_virtfn) | |
768 | return pseries_call_allow_unfreeze(edev); | |
769 | ||
770 | return 0; | |
771 | } | |
772 | #endif | |
773 | ||
aa1e6374 GS |
774 | static struct eeh_ops pseries_eeh_ops = { |
775 | .name = "pseries", | |
776 | .init = pseries_eeh_init, | |
ff57b454 | 777 | .probe = pseries_eeh_probe, |
aa1e6374 GS |
778 | .set_option = pseries_eeh_set_option, |
779 | .get_pe_addr = pseries_eeh_get_pe_addr, | |
780 | .get_state = pseries_eeh_get_state, | |
781 | .reset = pseries_eeh_reset, | |
aa1e6374 | 782 | .get_log = pseries_eeh_get_log, |
3780444c | 783 | .configure_bridge = pseries_eeh_configure_bridge, |
131c123a | 784 | .err_inject = NULL, |
3780444c | 785 | .read_config = pseries_eeh_read_config, |
1d350544 GS |
786 | .write_config = pseries_eeh_write_config, |
787 | .next_error = NULL, | |
67923cfc BL |
788 | .restore_config = pseries_eeh_restore_config, |
789 | #ifdef CONFIG_PCI_IOV | |
790 | .notify_resume = pseries_notify_resume | |
791 | #endif | |
aa1e6374 GS |
792 | }; |
793 | ||
794 | /** | |
795 | * eeh_pseries_init - Register platform dependent EEH operations | |
796 | * | |
797 | * EEH initialization on pseries platform. This function should be | |
798 | * called before any EEH related functions. | |
799 | */ | |
35e5cfe2 | 800 | static int __init eeh_pseries_init(void) |
aa1e6374 | 801 | { |
8e83e905 | 802 | int ret; |
3ea1ae98 GS |
803 | |
804 | ret = eeh_ops_register(&pseries_eeh_ops); | |
805 | if (!ret) | |
806 | pr_info("EEH: pSeries platform initialized\n"); | |
807 | else | |
808 | pr_info("EEH: pSeries platform initialization failure (%d)\n", | |
809 | ret); | |
810 | ||
811 | return ret; | |
aa1e6374 | 812 | } |
8e83e905 | 813 | machine_early_initcall(pseries, eeh_pseries_init); |