diff options
Diffstat (limited to 'arch/powerpc/platforms/powernv')
-rw-r--r-- | arch/powerpc/platforms/powernv/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/eeh-ioda.c | 916 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/eeh-powernv.c | 379 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/opal-wrappers.S | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/opal.c | 69 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci-ioda.c | 62 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci-p5ioc2.c | 11 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.c | 139 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.h | 35 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/setup.c | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/smp.c | 4 |
11 files changed, 1578 insertions, 45 deletions
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index bcc3cb48a44e..7fe595152478 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile | |||
@@ -3,3 +3,4 @@ obj-y += opal-rtc.o opal-nvram.o | |||
3 | 3 | ||
4 | obj-$(CONFIG_SMP) += smp.o | 4 | obj-$(CONFIG_SMP) += smp.o |
5 | obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o | 5 | obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o |
6 | obj-$(CONFIG_EEH) += eeh-ioda.o eeh-powernv.o | ||
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c new file mode 100644 index 000000000000..0cd1c4a71755 --- /dev/null +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c | |||
@@ -0,0 +1,916 @@ | |||
1 | /* | ||
2 | * The file intends to implement the functions needed by EEH, which is | ||
3 | * built on IODA compliant chip. Actually, lots of functions related | ||
4 | * to EEH would be built based on the OPAL APIs. | ||
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/bootmem.h> | ||
15 | #include <linux/debugfs.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/msi.h> | ||
22 | #include <linux/notifier.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/string.h> | ||
25 | |||
26 | #include <asm/eeh.h> | ||
27 | #include <asm/eeh_event.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/iommu.h> | ||
30 | #include <asm/msi_bitmap.h> | ||
31 | #include <asm/opal.h> | ||
32 | #include <asm/pci-bridge.h> | ||
33 | #include <asm/ppc-pci.h> | ||
34 | #include <asm/tce.h> | ||
35 | |||
36 | #include "powernv.h" | ||
37 | #include "pci.h" | ||
38 | |||
39 | /* Debugging option */ | ||
40 | #ifdef IODA_EEH_DBG_ON | ||
41 | #define IODA_EEH_DBG(args...) pr_info(args) | ||
42 | #else | ||
43 | #define IODA_EEH_DBG(args...) | ||
44 | #endif | ||
45 | |||
46 | static char *hub_diag = NULL; | ||
47 | static int ioda_eeh_nb_init = 0; | ||
48 | |||
49 | static int ioda_eeh_event(struct notifier_block *nb, | ||
50 | unsigned long events, void *change) | ||
51 | { | ||
52 | uint64_t changed_evts = (uint64_t)change; | ||
53 | |||
54 | /* We simply send special EEH event */ | ||
55 | if ((changed_evts & OPAL_EVENT_PCI_ERROR) && | ||
56 | (events & OPAL_EVENT_PCI_ERROR)) | ||
57 | eeh_send_failure_event(NULL); | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static struct notifier_block ioda_eeh_nb = { | ||
63 | .notifier_call = ioda_eeh_event, | ||
64 | .next = NULL, | ||
65 | .priority = 0 | ||
66 | }; | ||
67 | |||
68 | #ifdef CONFIG_DEBUG_FS | ||
69 | static int ioda_eeh_dbgfs_set(void *data, u64 val) | ||
70 | { | ||
71 | struct pci_controller *hose = data; | ||
72 | struct pnv_phb *phb = hose->private_data; | ||
73 | |||
74 | out_be64(phb->regs + 0xD10, val); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int ioda_eeh_dbgfs_get(void *data, u64 *val) | ||
79 | { | ||
80 | struct pci_controller *hose = data; | ||
81 | struct pnv_phb *phb = hose->private_data; | ||
82 | |||
83 | *val = in_be64(phb->regs + 0xD10); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_dbgfs_ops, ioda_eeh_dbgfs_get, | ||
88 | ioda_eeh_dbgfs_set, "0x%llx\n"); | ||
89 | #endif /* CONFIG_DEBUG_FS */ | ||
90 | |||
91 | /** | ||
92 | * ioda_eeh_post_init - Chip dependent post initialization | ||
93 | * @hose: PCI controller | ||
94 | * | ||
95 | * The function will be called after eeh PEs and devices | ||
96 | * have been built. That means the EEH is ready to supply | ||
97 | * service with I/O cache. | ||
98 | */ | ||
99 | static int ioda_eeh_post_init(struct pci_controller *hose) | ||
100 | { | ||
101 | struct pnv_phb *phb = hose->private_data; | ||
102 | int ret; | ||
103 | |||
104 | /* Register OPAL event notifier */ | ||
105 | if (!ioda_eeh_nb_init) { | ||
106 | ret = opal_notifier_register(&ioda_eeh_nb); | ||
107 | if (ret) { | ||
108 | pr_err("%s: Can't register OPAL event notifier (%d)\n", | ||
109 | __func__, ret); | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | ioda_eeh_nb_init = 1; | ||
114 | } | ||
115 | |||
116 | /* FIXME: Enable it for PHB3 later */ | ||
117 | if (phb->type == PNV_PHB_IODA1) { | ||
118 | if (!hub_diag) { | ||
119 | hub_diag = (char *)__get_free_page(GFP_KERNEL | | ||
120 | __GFP_ZERO); | ||
121 | if (!hub_diag) { | ||
122 | pr_err("%s: Out of memory !\n", | ||
123 | __func__); | ||
124 | return -ENOMEM; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | #ifdef CONFIG_DEBUG_FS | ||
129 | if (phb->dbgfs) | ||
130 | debugfs_create_file("err_injct", 0600, | ||
131 | phb->dbgfs, hose, | ||
132 | &ioda_eeh_dbgfs_ops); | ||
133 | #endif | ||
134 | |||
135 | phb->eeh_state |= PNV_EEH_STATE_ENABLED; | ||
136 | } | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * ioda_eeh_set_option - Set EEH operation or I/O setting | ||
143 | * @pe: EEH PE | ||
144 | * @option: options | ||
145 | * | ||
146 | * Enable or disable EEH option for the indicated PE. The | ||
147 | * function also can be used to enable I/O or DMA for the | ||
148 | * PE. | ||
149 | */ | ||
150 | static int ioda_eeh_set_option(struct eeh_pe *pe, int option) | ||
151 | { | ||
152 | s64 ret; | ||
153 | u32 pe_no; | ||
154 | struct pci_controller *hose = pe->phb; | ||
155 | struct pnv_phb *phb = hose->private_data; | ||
156 | |||
157 | /* Check on PE number */ | ||
158 | if (pe->addr < 0 || pe->addr >= phb->ioda.total_pe) { | ||
159 | pr_err("%s: PE address %x out of range [0, %x] " | ||
160 | "on PHB#%x\n", | ||
161 | __func__, pe->addr, phb->ioda.total_pe, | ||
162 | hose->global_number); | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | |||
166 | pe_no = pe->addr; | ||
167 | switch (option) { | ||
168 | case EEH_OPT_DISABLE: | ||
169 | ret = -EEXIST; | ||
170 | break; | ||
171 | case EEH_OPT_ENABLE: | ||
172 | ret = 0; | ||
173 | break; | ||
174 | case EEH_OPT_THAW_MMIO: | ||
175 | ret = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no, | ||
176 | OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO); | ||
177 | if (ret) { | ||
178 | pr_warning("%s: Failed to enable MMIO for " | ||
179 | "PHB#%x-PE#%x, err=%lld\n", | ||
180 | __func__, hose->global_number, pe_no, ret); | ||
181 | return -EIO; | ||
182 | } | ||
183 | |||
184 | break; | ||
185 | case EEH_OPT_THAW_DMA: | ||
186 | ret = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no, | ||
187 | OPAL_EEH_ACTION_CLEAR_FREEZE_DMA); | ||
188 | if (ret) { | ||
189 | pr_warning("%s: Failed to enable DMA for " | ||
190 | "PHB#%x-PE#%x, err=%lld\n", | ||
191 | __func__, hose->global_number, pe_no, ret); | ||
192 | return -EIO; | ||
193 | } | ||
194 | |||
195 | break; | ||
196 | default: | ||
197 | pr_warning("%s: Invalid option %d\n", __func__, option); | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | |||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * ioda_eeh_get_state - Retrieve the state of PE | ||
206 | * @pe: EEH PE | ||
207 | * | ||
208 | * The PE's state should be retrieved from the PEEV, PEST | ||
209 | * IODA tables. Since the OPAL has exported the function | ||
210 | * to do it, it'd better to use that. | ||
211 | */ | ||
212 | static int ioda_eeh_get_state(struct eeh_pe *pe) | ||
213 | { | ||
214 | s64 ret = 0; | ||
215 | u8 fstate; | ||
216 | u16 pcierr; | ||
217 | u32 pe_no; | ||
218 | int result; | ||
219 | struct pci_controller *hose = pe->phb; | ||
220 | struct pnv_phb *phb = hose->private_data; | ||
221 | |||
222 | /* | ||
223 | * Sanity check on PE address. The PHB PE address should | ||
224 | * be zero. | ||
225 | */ | ||
226 | if (pe->addr < 0 || pe->addr >= phb->ioda.total_pe) { | ||
227 | pr_err("%s: PE address %x out of range [0, %x] " | ||
228 | "on PHB#%x\n", | ||
229 | __func__, pe->addr, phb->ioda.total_pe, | ||
230 | hose->global_number); | ||
231 | return EEH_STATE_NOT_SUPPORT; | ||
232 | } | ||
233 | |||
234 | /* Retrieve PE status through OPAL */ | ||
235 | pe_no = pe->addr; | ||
236 | ret = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, | ||
237 | &fstate, &pcierr, NULL); | ||
238 | if (ret) { | ||
239 | pr_err("%s: Failed to get EEH status on " | ||
240 | "PHB#%x-PE#%x\n, err=%lld\n", | ||
241 | __func__, hose->global_number, pe_no, ret); | ||
242 | return EEH_STATE_NOT_SUPPORT; | ||
243 | } | ||
244 | |||
245 | /* Check PHB status */ | ||
246 | if (pe->type & EEH_PE_PHB) { | ||
247 | result = 0; | ||
248 | result &= ~EEH_STATE_RESET_ACTIVE; | ||
249 | |||
250 | if (pcierr != OPAL_EEH_PHB_ERROR) { | ||
251 | result |= EEH_STATE_MMIO_ACTIVE; | ||
252 | result |= EEH_STATE_DMA_ACTIVE; | ||
253 | result |= EEH_STATE_MMIO_ENABLED; | ||
254 | result |= EEH_STATE_DMA_ENABLED; | ||
255 | } | ||
256 | |||
257 | return result; | ||
258 | } | ||
259 | |||
260 | /* Parse result out */ | ||
261 | result = 0; | ||
262 | switch (fstate) { | ||
263 | case OPAL_EEH_STOPPED_NOT_FROZEN: | ||
264 | result &= ~EEH_STATE_RESET_ACTIVE; | ||
265 | result |= EEH_STATE_MMIO_ACTIVE; | ||
266 | result |= EEH_STATE_DMA_ACTIVE; | ||
267 | result |= EEH_STATE_MMIO_ENABLED; | ||
268 | result |= EEH_STATE_DMA_ENABLED; | ||
269 | break; | ||
270 | case OPAL_EEH_STOPPED_MMIO_FREEZE: | ||
271 | result &= ~EEH_STATE_RESET_ACTIVE; | ||
272 | result |= EEH_STATE_DMA_ACTIVE; | ||
273 | result |= EEH_STATE_DMA_ENABLED; | ||
274 | break; | ||
275 | case OPAL_EEH_STOPPED_DMA_FREEZE: | ||
276 | result &= ~EEH_STATE_RESET_ACTIVE; | ||
277 | result |= EEH_STATE_MMIO_ACTIVE; | ||
278 | result |= EEH_STATE_MMIO_ENABLED; | ||
279 | break; | ||
280 | case OPAL_EEH_STOPPED_MMIO_DMA_FREEZE: | ||
281 | result &= ~EEH_STATE_RESET_ACTIVE; | ||
282 | break; | ||
283 | case OPAL_EEH_STOPPED_RESET: | ||
284 | result |= EEH_STATE_RESET_ACTIVE; | ||
285 | break; | ||
286 | case OPAL_EEH_STOPPED_TEMP_UNAVAIL: | ||
287 | result |= EEH_STATE_UNAVAILABLE; | ||
288 | break; | ||
289 | case OPAL_EEH_STOPPED_PERM_UNAVAIL: | ||
290 | result |= EEH_STATE_NOT_SUPPORT; | ||
291 | break; | ||
292 | default: | ||
293 | pr_warning("%s: Unexpected EEH status 0x%x " | ||
294 | "on PHB#%x-PE#%x\n", | ||
295 | __func__, fstate, hose->global_number, pe_no); | ||
296 | } | ||
297 | |||
298 | return result; | ||
299 | } | ||
300 | |||
301 | static int ioda_eeh_pe_clear(struct eeh_pe *pe) | ||
302 | { | ||
303 | struct pci_controller *hose; | ||
304 | struct pnv_phb *phb; | ||
305 | u32 pe_no; | ||
306 | u8 fstate; | ||
307 | u16 pcierr; | ||
308 | s64 ret; | ||
309 | |||
310 | pe_no = pe->addr; | ||
311 | hose = pe->phb; | ||
312 | phb = pe->phb->private_data; | ||
313 | |||
314 | /* Clear the EEH error on the PE */ | ||
315 | ret = opal_pci_eeh_freeze_clear(phb->opal_id, | ||
316 | pe_no, OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); | ||
317 | if (ret) { | ||
318 | pr_err("%s: Failed to clear EEH error for " | ||
319 | "PHB#%x-PE#%x, err=%lld\n", | ||
320 | __func__, hose->global_number, pe_no, ret); | ||
321 | return -EIO; | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Read the PE state back and verify that the frozen | ||
326 | * state has been removed. | ||
327 | */ | ||
328 | ret = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, | ||
329 | &fstate, &pcierr, NULL); | ||
330 | if (ret) { | ||
331 | pr_err("%s: Failed to get EEH status on " | ||
332 | "PHB#%x-PE#%x\n, err=%lld\n", | ||
333 | __func__, hose->global_number, pe_no, ret); | ||
334 | return -EIO; | ||
335 | } | ||
336 | |||
337 | if (fstate != OPAL_EEH_STOPPED_NOT_FROZEN) { | ||
338 | pr_err("%s: Frozen state not cleared on " | ||
339 | "PHB#%x-PE#%x, sts=%x\n", | ||
340 | __func__, hose->global_number, pe_no, fstate); | ||
341 | return -EIO; | ||
342 | } | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static s64 ioda_eeh_phb_poll(struct pnv_phb *phb) | ||
348 | { | ||
349 | s64 rc = OPAL_HARDWARE; | ||
350 | |||
351 | while (1) { | ||
352 | rc = opal_pci_poll(phb->opal_id); | ||
353 | if (rc <= 0) | ||
354 | break; | ||
355 | |||
356 | msleep(rc); | ||
357 | } | ||
358 | |||
359 | return rc; | ||
360 | } | ||
361 | |||
362 | static int ioda_eeh_phb_reset(struct pci_controller *hose, int option) | ||
363 | { | ||
364 | struct pnv_phb *phb = hose->private_data; | ||
365 | s64 rc = OPAL_HARDWARE; | ||
366 | |||
367 | pr_debug("%s: Reset PHB#%x, option=%d\n", | ||
368 | __func__, hose->global_number, option); | ||
369 | |||
370 | /* Issue PHB complete reset request */ | ||
371 | if (option == EEH_RESET_FUNDAMENTAL || | ||
372 | option == EEH_RESET_HOT) | ||
373 | rc = opal_pci_reset(phb->opal_id, | ||
374 | OPAL_PHB_COMPLETE, | ||
375 | OPAL_ASSERT_RESET); | ||
376 | else if (option == EEH_RESET_DEACTIVATE) | ||
377 | rc = opal_pci_reset(phb->opal_id, | ||
378 | OPAL_PHB_COMPLETE, | ||
379 | OPAL_DEASSERT_RESET); | ||
380 | if (rc < 0) | ||
381 | goto out; | ||
382 | |||
383 | /* | ||
384 | * Poll state of the PHB until the request is done | ||
385 | * successfully. | ||
386 | */ | ||
387 | rc = ioda_eeh_phb_poll(phb); | ||
388 | out: | ||
389 | if (rc != OPAL_SUCCESS) | ||
390 | return -EIO; | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static int ioda_eeh_root_reset(struct pci_controller *hose, int option) | ||
396 | { | ||
397 | struct pnv_phb *phb = hose->private_data; | ||
398 | s64 rc = OPAL_SUCCESS; | ||
399 | |||
400 | pr_debug("%s: Reset PHB#%x, option=%d\n", | ||
401 | __func__, hose->global_number, option); | ||
402 | |||
403 | /* | ||
404 | * During the reset deassert time, we needn't care | ||
405 | * the reset scope because the firmware does nothing | ||
406 | * for fundamental or hot reset during deassert phase. | ||
407 | */ | ||
408 | if (option == EEH_RESET_FUNDAMENTAL) | ||
409 | rc = opal_pci_reset(phb->opal_id, | ||
410 | OPAL_PCI_FUNDAMENTAL_RESET, | ||
411 | OPAL_ASSERT_RESET); | ||
412 | else if (option == EEH_RESET_HOT) | ||
413 | rc = opal_pci_reset(phb->opal_id, | ||
414 | OPAL_PCI_HOT_RESET, | ||
415 | OPAL_ASSERT_RESET); | ||
416 | else if (option == EEH_RESET_DEACTIVATE) | ||
417 | rc = opal_pci_reset(phb->opal_id, | ||
418 | OPAL_PCI_HOT_RESET, | ||
419 | OPAL_DEASSERT_RESET); | ||
420 | if (rc < 0) | ||
421 | goto out; | ||
422 | |||
423 | /* Poll state of the PHB until the request is done */ | ||
424 | rc = ioda_eeh_phb_poll(phb); | ||
425 | out: | ||
426 | if (rc != OPAL_SUCCESS) | ||
427 | return -EIO; | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int ioda_eeh_bridge_reset(struct pci_controller *hose, | ||
433 | struct pci_dev *dev, int option) | ||
434 | { | ||
435 | u16 ctrl; | ||
436 | |||
437 | pr_debug("%s: Reset device %04x:%02x:%02x.%01x with option %d\n", | ||
438 | __func__, hose->global_number, dev->bus->number, | ||
439 | PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), option); | ||
440 | |||
441 | switch (option) { | ||
442 | case EEH_RESET_FUNDAMENTAL: | ||
443 | case EEH_RESET_HOT: | ||
444 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl); | ||
445 | ctrl |= PCI_BRIDGE_CTL_BUS_RESET; | ||
446 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl); | ||
447 | break; | ||
448 | case EEH_RESET_DEACTIVATE: | ||
449 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl); | ||
450 | ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; | ||
451 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl); | ||
452 | break; | ||
453 | } | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | /** | ||
459 | * ioda_eeh_reset - Reset the indicated PE | ||
460 | * @pe: EEH PE | ||
461 | * @option: reset option | ||
462 | * | ||
463 | * Do reset on the indicated PE. For PCI bus sensitive PE, | ||
464 | * we need to reset the parent p2p bridge. The PHB has to | ||
465 | * be reinitialized if the p2p bridge is root bridge. For | ||
466 | * PCI device sensitive PE, we will try to reset the device | ||
467 | * through FLR. For now, we don't have OPAL APIs to do HARD | ||
468 | * reset yet, so all reset would be SOFT (HOT) reset. | ||
469 | */ | ||
470 | static int ioda_eeh_reset(struct eeh_pe *pe, int option) | ||
471 | { | ||
472 | struct pci_controller *hose = pe->phb; | ||
473 | struct eeh_dev *edev; | ||
474 | struct pci_dev *dev; | ||
475 | int ret; | ||
476 | |||
477 | /* | ||
478 | * Anyway, we have to clear the problematic state for the | ||
479 | * corresponding PE. However, we needn't do it if the PE | ||
480 | * is PHB associated. That means the PHB is having fatal | ||
481 | * errors and it needs reset. Further more, the AIB interface | ||
482 | * isn't reliable any more. | ||
483 | */ | ||
484 | if (!(pe->type & EEH_PE_PHB) && | ||
485 | (option == EEH_RESET_HOT || | ||
486 | option == EEH_RESET_FUNDAMENTAL)) { | ||
487 | ret = ioda_eeh_pe_clear(pe); | ||
488 | if (ret) | ||
489 | return -EIO; | ||
490 | } | ||
491 | |||
492 | /* | ||
493 | * The rules applied to reset, either fundamental or hot reset: | ||
494 | * | ||
495 | * We always reset the direct upstream bridge of the PE. If the | ||
496 | * direct upstream bridge isn't root bridge, we always take hot | ||
497 | * reset no matter what option (fundamental or hot) is. Otherwise, | ||
498 | * we should do the reset according to the required option. | ||
499 | */ | ||
500 | if (pe->type & EEH_PE_PHB) { | ||
501 | ret = ioda_eeh_phb_reset(hose, option); | ||
502 | } else { | ||
503 | if (pe->type & EEH_PE_DEVICE) { | ||
504 | /* | ||
505 | * If it's device PE, we didn't refer to the parent | ||
506 | * PCI bus yet. So we have to figure it out indirectly. | ||
507 | */ | ||
508 | edev = list_first_entry(&pe->edevs, | ||
509 | struct eeh_dev, list); | ||
510 | dev = eeh_dev_to_pci_dev(edev); | ||
511 | dev = dev->bus->self; | ||
512 | } else { | ||
513 | /* | ||
514 | * If it's bus PE, the parent PCI bus is already there | ||
515 | * and just pick it up. | ||
516 | */ | ||
517 | dev = pe->bus->self; | ||
518 | } | ||
519 | |||
520 | /* | ||
521 | * Do reset based on the fact that the direct upstream bridge | ||
522 | * is root bridge (port) or not. | ||
523 | */ | ||
524 | if (dev->bus->number == 0) | ||
525 | ret = ioda_eeh_root_reset(hose, option); | ||
526 | else | ||
527 | ret = ioda_eeh_bridge_reset(hose, dev, option); | ||
528 | } | ||
529 | |||
530 | return ret; | ||
531 | } | ||
532 | |||
533 | /** | ||
534 | * ioda_eeh_get_log - Retrieve error log | ||
535 | * @pe: EEH PE | ||
536 | * @severity: Severity level of the log | ||
537 | * @drv_log: buffer to store the log | ||
538 | * @len: space of the log buffer | ||
539 | * | ||
540 | * The function is used to retrieve error log from P7IOC. | ||
541 | */ | ||
542 | static int ioda_eeh_get_log(struct eeh_pe *pe, int severity, | ||
543 | char *drv_log, unsigned long len) | ||
544 | { | ||
545 | s64 ret; | ||
546 | unsigned long flags; | ||
547 | struct pci_controller *hose = pe->phb; | ||
548 | struct pnv_phb *phb = hose->private_data; | ||
549 | |||
550 | spin_lock_irqsave(&phb->lock, flags); | ||
551 | |||
552 | ret = opal_pci_get_phb_diag_data2(phb->opal_id, | ||
553 | phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE); | ||
554 | if (ret) { | ||
555 | spin_unlock_irqrestore(&phb->lock, flags); | ||
556 | pr_warning("%s: Failed to get log for PHB#%x-PE#%x\n", | ||
557 | __func__, hose->global_number, pe->addr); | ||
558 | return -EIO; | ||
559 | } | ||
560 | |||
561 | /* | ||
562 | * FIXME: We probably need log the error in somewhere. | ||
563 | * Lets make it up in future. | ||
564 | */ | ||
565 | /* pr_info("%s", phb->diag.blob); */ | ||
566 | |||
567 | spin_unlock_irqrestore(&phb->lock, flags); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | /** | ||
573 | * ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE | ||
574 | * @pe: EEH PE | ||
575 | * | ||
576 | * For particular PE, it might have included PCI bridges. In order | ||
577 | * to make the PE work properly, those PCI bridges should be configured | ||
578 | * correctly. However, we need do nothing on P7IOC since the reset | ||
579 | * function will do everything that should be covered by the function. | ||
580 | */ | ||
581 | static int ioda_eeh_configure_bridge(struct eeh_pe *pe) | ||
582 | { | ||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static void ioda_eeh_hub_diag_common(struct OpalIoP7IOCErrorData *data) | ||
587 | { | ||
588 | /* GEM */ | ||
589 | pr_info(" GEM XFIR: %016llx\n", data->gemXfir); | ||
590 | pr_info(" GEM RFIR: %016llx\n", data->gemRfir); | ||
591 | pr_info(" GEM RIRQFIR: %016llx\n", data->gemRirqfir); | ||
592 | pr_info(" GEM Mask: %016llx\n", data->gemMask); | ||
593 | pr_info(" GEM RWOF: %016llx\n", data->gemRwof); | ||
594 | |||
595 | /* LEM */ | ||
596 | pr_info(" LEM FIR: %016llx\n", data->lemFir); | ||
597 | pr_info(" LEM Error Mask: %016llx\n", data->lemErrMask); | ||
598 | pr_info(" LEM Action 0: %016llx\n", data->lemAction0); | ||
599 | pr_info(" LEM Action 1: %016llx\n", data->lemAction1); | ||
600 | pr_info(" LEM WOF: %016llx\n", data->lemWof); | ||
601 | } | ||
602 | |||
603 | static void ioda_eeh_hub_diag(struct pci_controller *hose) | ||
604 | { | ||
605 | struct pnv_phb *phb = hose->private_data; | ||
606 | struct OpalIoP7IOCErrorData *data; | ||
607 | long rc; | ||
608 | |||
609 | data = (struct OpalIoP7IOCErrorData *)ioda_eeh_hub_diag; | ||
610 | rc = opal_pci_get_hub_diag_data(phb->hub_id, data, PAGE_SIZE); | ||
611 | if (rc != OPAL_SUCCESS) { | ||
612 | pr_warning("%s: Failed to get HUB#%llx diag-data (%ld)\n", | ||
613 | __func__, phb->hub_id, rc); | ||
614 | return; | ||
615 | } | ||
616 | |||
617 | switch (data->type) { | ||
618 | case OPAL_P7IOC_DIAG_TYPE_RGC: | ||
619 | pr_info("P7IOC diag-data for RGC\n\n"); | ||
620 | ioda_eeh_hub_diag_common(data); | ||
621 | pr_info(" RGC Status: %016llx\n", data->rgc.rgcStatus); | ||
622 | pr_info(" RGC LDCP: %016llx\n", data->rgc.rgcLdcp); | ||
623 | break; | ||
624 | case OPAL_P7IOC_DIAG_TYPE_BI: | ||
625 | pr_info("P7IOC diag-data for BI %s\n\n", | ||
626 | data->bi.biDownbound ? "Downbound" : "Upbound"); | ||
627 | ioda_eeh_hub_diag_common(data); | ||
628 | pr_info(" BI LDCP 0: %016llx\n", data->bi.biLdcp0); | ||
629 | pr_info(" BI LDCP 1: %016llx\n", data->bi.biLdcp1); | ||
630 | pr_info(" BI LDCP 2: %016llx\n", data->bi.biLdcp2); | ||
631 | pr_info(" BI Fence Status: %016llx\n", data->bi.biFenceStatus); | ||
632 | break; | ||
633 | case OPAL_P7IOC_DIAG_TYPE_CI: | ||
634 | pr_info("P7IOC diag-data for CI Port %d\\nn", | ||
635 | data->ci.ciPort); | ||
636 | ioda_eeh_hub_diag_common(data); | ||
637 | pr_info(" CI Port Status: %016llx\n", data->ci.ciPortStatus); | ||
638 | pr_info(" CI Port LDCP: %016llx\n", data->ci.ciPortLdcp); | ||
639 | break; | ||
640 | case OPAL_P7IOC_DIAG_TYPE_MISC: | ||
641 | pr_info("P7IOC diag-data for MISC\n\n"); | ||
642 | ioda_eeh_hub_diag_common(data); | ||
643 | break; | ||
644 | case OPAL_P7IOC_DIAG_TYPE_I2C: | ||
645 | pr_info("P7IOC diag-data for I2C\n\n"); | ||
646 | ioda_eeh_hub_diag_common(data); | ||
647 | break; | ||
648 | default: | ||
649 | pr_warning("%s: Invalid type of HUB#%llx diag-data (%d)\n", | ||
650 | __func__, phb->hub_id, data->type); | ||
651 | } | ||
652 | } | ||
653 | |||
654 | static void ioda_eeh_p7ioc_phb_diag(struct pci_controller *hose, | ||
655 | struct OpalIoPhbErrorCommon *common) | ||
656 | { | ||
657 | struct OpalIoP7IOCPhbErrorData *data; | ||
658 | int i; | ||
659 | |||
660 | data = (struct OpalIoP7IOCPhbErrorData *)common; | ||
661 | |||
662 | pr_info("P7IOC PHB#%x Diag-data (Version: %d)\n\n", | ||
663 | hose->global_number, common->version); | ||
664 | |||
665 | pr_info(" brdgCtl: %08x\n", data->brdgCtl); | ||
666 | |||
667 | pr_info(" portStatusReg: %08x\n", data->portStatusReg); | ||
668 | pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus); | ||
669 | pr_info(" busAgentStatus: %08x\n", data->busAgentStatus); | ||
670 | |||
671 | pr_info(" deviceStatus: %08x\n", data->deviceStatus); | ||
672 | pr_info(" slotStatus: %08x\n", data->slotStatus); | ||
673 | pr_info(" linkStatus: %08x\n", data->linkStatus); | ||
674 | pr_info(" devCmdStatus: %08x\n", data->devCmdStatus); | ||
675 | pr_info(" devSecStatus: %08x\n", data->devSecStatus); | ||
676 | |||
677 | pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus); | ||
678 | pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus); | ||
679 | pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus); | ||
680 | pr_info(" tlpHdr1: %08x\n", data->tlpHdr1); | ||
681 | pr_info(" tlpHdr2: %08x\n", data->tlpHdr2); | ||
682 | pr_info(" tlpHdr3: %08x\n", data->tlpHdr3); | ||
683 | pr_info(" tlpHdr4: %08x\n", data->tlpHdr4); | ||
684 | pr_info(" sourceId: %08x\n", data->sourceId); | ||
685 | |||
686 | pr_info(" errorClass: %016llx\n", data->errorClass); | ||
687 | pr_info(" correlator: %016llx\n", data->correlator); | ||
688 | pr_info(" p7iocPlssr: %016llx\n", data->p7iocPlssr); | ||
689 | pr_info(" p7iocCsr: %016llx\n", data->p7iocCsr); | ||
690 | pr_info(" lemFir: %016llx\n", data->lemFir); | ||
691 | pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask); | ||
692 | pr_info(" lemWOF: %016llx\n", data->lemWOF); | ||
693 | pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus); | ||
694 | pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus); | ||
695 | pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0); | ||
696 | pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1); | ||
697 | pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus); | ||
698 | pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus); | ||
699 | pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0); | ||
700 | pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1); | ||
701 | pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus); | ||
702 | pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus); | ||
703 | pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0); | ||
704 | pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1); | ||
705 | pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus); | ||
706 | pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus); | ||
707 | pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0); | ||
708 | pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1); | ||
709 | |||
710 | for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) { | ||
711 | if ((data->pestA[i] >> 63) == 0 && | ||
712 | (data->pestB[i] >> 63) == 0) | ||
713 | continue; | ||
714 | |||
715 | pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]); | ||
716 | pr_info(" PESTB: %016llx\n", data->pestB[i]); | ||
717 | } | ||
718 | } | ||
719 | |||
720 | static void ioda_eeh_phb_diag(struct pci_controller *hose) | ||
721 | { | ||
722 | struct pnv_phb *phb = hose->private_data; | ||
723 | struct OpalIoPhbErrorCommon *common; | ||
724 | long rc; | ||
725 | |||
726 | common = (struct OpalIoPhbErrorCommon *)phb->diag.blob; | ||
727 | rc = opal_pci_get_phb_diag_data2(phb->opal_id, common, PAGE_SIZE); | ||
728 | if (rc != OPAL_SUCCESS) { | ||
729 | pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n", | ||
730 | __func__, hose->global_number, rc); | ||
731 | return; | ||
732 | } | ||
733 | |||
734 | switch (common->ioType) { | ||
735 | case OPAL_PHB_ERROR_DATA_TYPE_P7IOC: | ||
736 | ioda_eeh_p7ioc_phb_diag(hose, common); | ||
737 | break; | ||
738 | default: | ||
739 | pr_warning("%s: Unrecognized I/O chip %d\n", | ||
740 | __func__, common->ioType); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | static int ioda_eeh_get_phb_pe(struct pci_controller *hose, | ||
745 | struct eeh_pe **pe) | ||
746 | { | ||
747 | struct eeh_pe *phb_pe; | ||
748 | |||
749 | phb_pe = eeh_phb_pe_get(hose); | ||
750 | if (!phb_pe) { | ||
751 | pr_warning("%s Can't find PE for PHB#%d\n", | ||
752 | __func__, hose->global_number); | ||
753 | return -EEXIST; | ||
754 | } | ||
755 | |||
756 | *pe = phb_pe; | ||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | static int ioda_eeh_get_pe(struct pci_controller *hose, | ||
761 | u16 pe_no, struct eeh_pe **pe) | ||
762 | { | ||
763 | struct eeh_pe *phb_pe, *dev_pe; | ||
764 | struct eeh_dev dev; | ||
765 | |||
766 | /* Find the PHB PE */ | ||
767 | if (ioda_eeh_get_phb_pe(hose, &phb_pe)) | ||
768 | return -EEXIST; | ||
769 | |||
770 | /* Find the PE according to PE# */ | ||
771 | memset(&dev, 0, sizeof(struct eeh_dev)); | ||
772 | dev.phb = hose; | ||
773 | dev.pe_config_addr = pe_no; | ||
774 | dev_pe = eeh_pe_get(&dev); | ||
775 | if (!dev_pe) { | ||
776 | pr_warning("%s: Can't find PE for PHB#%x - PE#%x\n", | ||
777 | __func__, hose->global_number, pe_no); | ||
778 | return -EEXIST; | ||
779 | } | ||
780 | |||
781 | *pe = dev_pe; | ||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | /** | ||
786 | * ioda_eeh_next_error - Retrieve next error for EEH core to handle | ||
787 | * @pe: The affected PE | ||
788 | * | ||
789 | * The function is expected to be called by EEH core while it gets | ||
790 | * special EEH event (without binding PE). The function calls to | ||
791 | * OPAL APIs for next error to handle. The informational error is | ||
792 | * handled internally by platform. However, the dead IOC, dead PHB, | ||
793 | * fenced PHB and frozen PE should be handled by EEH core eventually. | ||
794 | */ | ||
795 | static int ioda_eeh_next_error(struct eeh_pe **pe) | ||
796 | { | ||
797 | struct pci_controller *hose, *tmp; | ||
798 | struct pnv_phb *phb; | ||
799 | u64 frozen_pe_no; | ||
800 | u16 err_type, severity; | ||
801 | long rc; | ||
802 | int ret = 1; | ||
803 | |||
804 | /* | ||
805 | * While running here, it's safe to purge the event queue. | ||
806 | * And we should keep the cached OPAL notifier event sychronized | ||
807 | * between the kernel and firmware. | ||
808 | */ | ||
809 | eeh_remove_event(NULL); | ||
810 | opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul); | ||
811 | |||
812 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | ||
813 | /* | ||
814 | * If the subordinate PCI buses of the PHB has been | ||
815 | * removed, we needn't take care of it any more. | ||
816 | */ | ||
817 | phb = hose->private_data; | ||
818 | if (phb->eeh_state & PNV_EEH_STATE_REMOVED) | ||
819 | continue; | ||
820 | |||
821 | rc = opal_pci_next_error(phb->opal_id, | ||
822 | &frozen_pe_no, &err_type, &severity); | ||
823 | |||
824 | /* If OPAL API returns error, we needn't proceed */ | ||
825 | if (rc != OPAL_SUCCESS) { | ||
826 | IODA_EEH_DBG("%s: Invalid return value on " | ||
827 | "PHB#%x (0x%lx) from opal_pci_next_error", | ||
828 | __func__, hose->global_number, rc); | ||
829 | continue; | ||
830 | } | ||
831 | |||
832 | /* If the PHB doesn't have error, stop processing */ | ||
833 | if (err_type == OPAL_EEH_NO_ERROR || | ||
834 | severity == OPAL_EEH_SEV_NO_ERROR) { | ||
835 | IODA_EEH_DBG("%s: No error found on PHB#%x\n", | ||
836 | __func__, hose->global_number); | ||
837 | continue; | ||
838 | } | ||
839 | |||
840 | /* | ||
841 | * Processing the error. We're expecting the error with | ||
842 | * highest priority reported upon multiple errors on the | ||
843 | * specific PHB. | ||
844 | */ | ||
845 | IODA_EEH_DBG("%s: Error (%d, %d, %d) on PHB#%x\n", | ||
846 | err_type, severity, pe_no, hose->global_number); | ||
847 | switch (err_type) { | ||
848 | case OPAL_EEH_IOC_ERROR: | ||
849 | if (severity == OPAL_EEH_SEV_IOC_DEAD) { | ||
850 | list_for_each_entry_safe(hose, tmp, | ||
851 | &hose_list, list_node) { | ||
852 | phb = hose->private_data; | ||
853 | phb->eeh_state |= PNV_EEH_STATE_REMOVED; | ||
854 | } | ||
855 | |||
856 | pr_err("EEH: dead IOC detected\n"); | ||
857 | ret = 4; | ||
858 | goto out; | ||
859 | } else if (severity == OPAL_EEH_SEV_INF) { | ||
860 | pr_info("EEH: IOC informative error " | ||
861 | "detected\n"); | ||
862 | ioda_eeh_hub_diag(hose); | ||
863 | } | ||
864 | |||
865 | break; | ||
866 | case OPAL_EEH_PHB_ERROR: | ||
867 | if (severity == OPAL_EEH_SEV_PHB_DEAD) { | ||
868 | if (ioda_eeh_get_phb_pe(hose, pe)) | ||
869 | break; | ||
870 | |||
871 | pr_err("EEH: dead PHB#%x detected\n", | ||
872 | hose->global_number); | ||
873 | phb->eeh_state |= PNV_EEH_STATE_REMOVED; | ||
874 | ret = 3; | ||
875 | goto out; | ||
876 | } else if (severity == OPAL_EEH_SEV_PHB_FENCED) { | ||
877 | if (ioda_eeh_get_phb_pe(hose, pe)) | ||
878 | break; | ||
879 | |||
880 | pr_err("EEH: fenced PHB#%x detected\n", | ||
881 | hose->global_number); | ||
882 | ret = 2; | ||
883 | goto out; | ||
884 | } else if (severity == OPAL_EEH_SEV_INF) { | ||
885 | pr_info("EEH: PHB#%x informative error " | ||
886 | "detected\n", | ||
887 | hose->global_number); | ||
888 | ioda_eeh_phb_diag(hose); | ||
889 | } | ||
890 | |||
891 | break; | ||
892 | case OPAL_EEH_PE_ERROR: | ||
893 | if (ioda_eeh_get_pe(hose, frozen_pe_no, pe)) | ||
894 | break; | ||
895 | |||
896 | pr_err("EEH: Frozen PE#%x on PHB#%x detected\n", | ||
897 | (*pe)->addr, (*pe)->phb->global_number); | ||
898 | ret = 1; | ||
899 | goto out; | ||
900 | } | ||
901 | } | ||
902 | |||
903 | ret = 0; | ||
904 | out: | ||
905 | return ret; | ||
906 | } | ||
907 | |||
908 | struct pnv_eeh_ops ioda_eeh_ops = { | ||
909 | .post_init = ioda_eeh_post_init, | ||
910 | .set_option = ioda_eeh_set_option, | ||
911 | .get_state = ioda_eeh_get_state, | ||
912 | .reset = ioda_eeh_reset, | ||
913 | .get_log = ioda_eeh_get_log, | ||
914 | .configure_bridge = ioda_eeh_configure_bridge, | ||
915 | .next_error = ioda_eeh_next_error | ||
916 | }; | ||
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c new file mode 100644 index 000000000000..969cce73055a --- /dev/null +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c | |||
@@ -0,0 +1,379 @@ | |||
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 | { | ||
48 | /* We require OPALv3 */ | ||
49 | if (!firmware_has_feature(FW_FEATURE_OPALv3)) { | ||
50 | pr_warning("%s: OPALv3 is required !\n", __func__); | ||
51 | return -EINVAL; | ||
52 | } | ||
53 | |||
54 | /* Set EEH probe mode */ | ||
55 | eeh_probe_mode_set(EEH_PROBE_MODE_DEV); | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * powernv_eeh_post_init - EEH platform dependent post initialization | ||
62 | * | ||
63 | * EEH platform dependent post initialization on powernv. When | ||
64 | * the function is called, the EEH PEs and devices should have | ||
65 | * been built. If the I/O cache staff has been built, EEH is | ||
66 | * ready to supply service. | ||
67 | */ | ||
68 | static int powernv_eeh_post_init(void) | ||
69 | { | ||
70 | struct pci_controller *hose; | ||
71 | struct pnv_phb *phb; | ||
72 | int ret = 0; | ||
73 | |||
74 | list_for_each_entry(hose, &hose_list, list_node) { | ||
75 | phb = hose->private_data; | ||
76 | |||
77 | if (phb->eeh_ops && phb->eeh_ops->post_init) { | ||
78 | ret = phb->eeh_ops->post_init(hose); | ||
79 | if (ret) | ||
80 | break; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * powernv_eeh_dev_probe - Do probe on PCI device | ||
89 | * @dev: PCI device | ||
90 | * @flag: unused | ||
91 | * | ||
92 | * When EEH module is installed during system boot, all PCI devices | ||
93 | * are checked one by one to see if it supports EEH. The function | ||
94 | * is introduced for the purpose. By default, EEH has been enabled | ||
95 | * on all PCI devices. That's to say, we only need do necessary | ||
96 | * initialization on the corresponding eeh device and create PE | ||
97 | * accordingly. | ||
98 | * | ||
99 | * It's notable that's unsafe to retrieve the EEH device through | ||
100 | * the corresponding PCI device. During the PCI device hotplug, which | ||
101 | * was possiblly triggered by EEH core, the binding between EEH device | ||
102 | * and the PCI device isn't built yet. | ||
103 | */ | ||
104 | static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) | ||
105 | { | ||
106 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | ||
107 | struct pnv_phb *phb = hose->private_data; | ||
108 | struct device_node *dn = pci_device_to_OF_node(dev); | ||
109 | struct eeh_dev *edev = of_node_to_eeh_dev(dn); | ||
110 | |||
111 | /* | ||
112 | * When probing the root bridge, which doesn't have any | ||
113 | * subordinate PCI devices. We don't have OF node for | ||
114 | * the root bridge. So it's not reasonable to continue | ||
115 | * the probing. | ||
116 | */ | ||
117 | if (!dn || !edev) | ||
118 | return 0; | ||
119 | |||
120 | /* Skip for PCI-ISA bridge */ | ||
121 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_ISA) | ||
122 | return 0; | ||
123 | |||
124 | /* Initialize eeh device */ | ||
125 | edev->class_code = dev->class; | ||
126 | edev->mode = 0; | ||
127 | edev->config_addr = ((dev->bus->number << 8) | dev->devfn); | ||
128 | edev->pe_config_addr = phb->bdfn_to_pe(phb, dev->bus, dev->devfn & 0xff); | ||
129 | |||
130 | /* Create PE */ | ||
131 | eeh_add_to_parent_pe(edev); | ||
132 | |||
133 | /* | ||
134 | * Enable EEH explicitly so that we will do EEH check | ||
135 | * while accessing I/O stuff | ||
136 | * | ||
137 | * FIXME: Enable that for PHB3 later | ||
138 | */ | ||
139 | if (phb->type == PNV_PHB_IODA1) | ||
140 | eeh_subsystem_enabled = 1; | ||
141 | |||
142 | /* Save memory bars */ | ||
143 | eeh_save_bars(edev); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * powernv_eeh_set_option - Initialize EEH or MMIO/DMA reenable | ||
150 | * @pe: EEH PE | ||
151 | * @option: operation to be issued | ||
152 | * | ||
153 | * The function is used to control the EEH functionality globally. | ||
154 | * Currently, following options are support according to PAPR: | ||
155 | * Enable EEH, Disable EEH, Enable MMIO and Enable DMA | ||
156 | */ | ||
157 | static int powernv_eeh_set_option(struct eeh_pe *pe, int option) | ||
158 | { | ||
159 | struct pci_controller *hose = pe->phb; | ||
160 | struct pnv_phb *phb = hose->private_data; | ||
161 | int ret = -EEXIST; | ||
162 | |||
163 | /* | ||
164 | * What we need do is pass it down for hardware | ||
165 | * implementation to handle it. | ||
166 | */ | ||
167 | if (phb->eeh_ops && phb->eeh_ops->set_option) | ||
168 | ret = phb->eeh_ops->set_option(pe, option); | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * powernv_eeh_get_pe_addr - Retrieve PE address | ||
175 | * @pe: EEH PE | ||
176 | * | ||
177 | * Retrieve the PE address according to the given tranditional | ||
178 | * PCI BDF (Bus/Device/Function) address. | ||
179 | */ | ||
180 | static int powernv_eeh_get_pe_addr(struct eeh_pe *pe) | ||
181 | { | ||
182 | return pe->addr; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * powernv_eeh_get_state - Retrieve PE state | ||
187 | * @pe: EEH PE | ||
188 | * @delay: delay while PE state is temporarily unavailable | ||
189 | * | ||
190 | * Retrieve the state of the specified PE. For IODA-compitable | ||
191 | * platform, it should be retrieved from IODA table. Therefore, | ||
192 | * we prefer passing down to hardware implementation to handle | ||
193 | * it. | ||
194 | */ | ||
195 | static int powernv_eeh_get_state(struct eeh_pe *pe, int *delay) | ||
196 | { | ||
197 | struct pci_controller *hose = pe->phb; | ||
198 | struct pnv_phb *phb = hose->private_data; | ||
199 | int ret = EEH_STATE_NOT_SUPPORT; | ||
200 | |||
201 | if (phb->eeh_ops && phb->eeh_ops->get_state) { | ||
202 | ret = phb->eeh_ops->get_state(pe); | ||
203 | |||
204 | /* | ||
205 | * If the PE state is temporarily unavailable, | ||
206 | * to inform the EEH core delay for default | ||
207 | * period (1 second) | ||
208 | */ | ||
209 | if (delay) { | ||
210 | *delay = 0; | ||
211 | if (ret & EEH_STATE_UNAVAILABLE) | ||
212 | *delay = 1000; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * powernv_eeh_reset - Reset the specified PE | ||
221 | * @pe: EEH PE | ||
222 | * @option: reset option | ||
223 | * | ||
224 | * Reset the specified PE | ||
225 | */ | ||
226 | static int powernv_eeh_reset(struct eeh_pe *pe, int option) | ||
227 | { | ||
228 | struct pci_controller *hose = pe->phb; | ||
229 | struct pnv_phb *phb = hose->private_data; | ||
230 | int ret = -EEXIST; | ||
231 | |||
232 | if (phb->eeh_ops && phb->eeh_ops->reset) | ||
233 | ret = phb->eeh_ops->reset(pe, option); | ||
234 | |||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | /** | ||
239 | * powernv_eeh_wait_state - Wait for PE state | ||
240 | * @pe: EEH PE | ||
241 | * @max_wait: maximal period in microsecond | ||
242 | * | ||
243 | * Wait for the state of associated PE. It might take some time | ||
244 | * to retrieve the PE's state. | ||
245 | */ | ||
246 | static int powernv_eeh_wait_state(struct eeh_pe *pe, int max_wait) | ||
247 | { | ||
248 | int ret; | ||
249 | int mwait; | ||
250 | |||
251 | while (1) { | ||
252 | ret = powernv_eeh_get_state(pe, &mwait); | ||
253 | |||
254 | /* | ||
255 | * If the PE's state is temporarily unavailable, | ||
256 | * we have to wait for the specified time. Otherwise, | ||
257 | * the PE's state will be returned immediately. | ||
258 | */ | ||
259 | if (ret != EEH_STATE_UNAVAILABLE) | ||
260 | return ret; | ||
261 | |||
262 | max_wait -= mwait; | ||
263 | if (max_wait <= 0) { | ||
264 | pr_warning("%s: Timeout getting PE#%x's state (%d)\n", | ||
265 | __func__, pe->addr, max_wait); | ||
266 | return EEH_STATE_NOT_SUPPORT; | ||
267 | } | ||
268 | |||
269 | msleep(mwait); | ||
270 | } | ||
271 | |||
272 | return EEH_STATE_NOT_SUPPORT; | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * powernv_eeh_get_log - Retrieve error log | ||
277 | * @pe: EEH PE | ||
278 | * @severity: temporary or permanent error log | ||
279 | * @drv_log: driver log to be combined with retrieved error log | ||
280 | * @len: length of driver log | ||
281 | * | ||
282 | * Retrieve the temporary or permanent error from the PE. | ||
283 | */ | ||
284 | static int powernv_eeh_get_log(struct eeh_pe *pe, int severity, | ||
285 | char *drv_log, unsigned long len) | ||
286 | { | ||
287 | struct pci_controller *hose = pe->phb; | ||
288 | struct pnv_phb *phb = hose->private_data; | ||
289 | int ret = -EEXIST; | ||
290 | |||
291 | if (phb->eeh_ops && phb->eeh_ops->get_log) | ||
292 | ret = phb->eeh_ops->get_log(pe, severity, drv_log, len); | ||
293 | |||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * powernv_eeh_configure_bridge - Configure PCI bridges in the indicated PE | ||
299 | * @pe: EEH PE | ||
300 | * | ||
301 | * The function will be called to reconfigure the bridges included | ||
302 | * in the specified PE so that the mulfunctional PE would be recovered | ||
303 | * again. | ||
304 | */ | ||
305 | static int powernv_eeh_configure_bridge(struct eeh_pe *pe) | ||
306 | { | ||
307 | struct pci_controller *hose = pe->phb; | ||
308 | struct pnv_phb *phb = hose->private_data; | ||
309 | int ret = 0; | ||
310 | |||
311 | if (phb->eeh_ops && phb->eeh_ops->configure_bridge) | ||
312 | ret = phb->eeh_ops->configure_bridge(pe); | ||
313 | |||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | /** | ||
318 | * powernv_eeh_next_error - Retrieve next EEH error to handle | ||
319 | * @pe: Affected PE | ||
320 | * | ||
321 | * Using OPAL API, to retrieve next EEH error for EEH core to handle | ||
322 | */ | ||
323 | static int powernv_eeh_next_error(struct eeh_pe **pe) | ||
324 | { | ||
325 | struct pci_controller *hose; | ||
326 | struct pnv_phb *phb = NULL; | ||
327 | |||
328 | list_for_each_entry(hose, &hose_list, list_node) { | ||
329 | phb = hose->private_data; | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | if (phb && phb->eeh_ops->next_error) | ||
334 | return phb->eeh_ops->next_error(pe); | ||
335 | |||
336 | return -EEXIST; | ||
337 | } | ||
338 | |||
339 | static struct eeh_ops powernv_eeh_ops = { | ||
340 | .name = "powernv", | ||
341 | .init = powernv_eeh_init, | ||
342 | .post_init = powernv_eeh_post_init, | ||
343 | .of_probe = NULL, | ||
344 | .dev_probe = powernv_eeh_dev_probe, | ||
345 | .set_option = powernv_eeh_set_option, | ||
346 | .get_pe_addr = powernv_eeh_get_pe_addr, | ||
347 | .get_state = powernv_eeh_get_state, | ||
348 | .reset = powernv_eeh_reset, | ||
349 | .wait_state = powernv_eeh_wait_state, | ||
350 | .get_log = powernv_eeh_get_log, | ||
351 | .configure_bridge = powernv_eeh_configure_bridge, | ||
352 | .read_config = pnv_pci_cfg_read, | ||
353 | .write_config = pnv_pci_cfg_write, | ||
354 | .next_error = powernv_eeh_next_error | ||
355 | }; | ||
356 | |||
357 | /** | ||
358 | * eeh_powernv_init - Register platform dependent EEH operations | ||
359 | * | ||
360 | * EEH initialization on powernv platform. This function should be | ||
361 | * called before any EEH related functions. | ||
362 | */ | ||
363 | static int __init eeh_powernv_init(void) | ||
364 | { | ||
365 | int ret = -EINVAL; | ||
366 | |||
367 | if (!machine_is(powernv)) | ||
368 | return ret; | ||
369 | |||
370 | ret = eeh_ops_register(&powernv_eeh_ops); | ||
371 | if (!ret) | ||
372 | pr_info("EEH: PowerNV platform initialized\n"); | ||
373 | else | ||
374 | pr_info("EEH: Failed to initialize PowerNV platform (%d)\n", ret); | ||
375 | |||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | early_initcall(eeh_powernv_init); | ||
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index 6fabe92eafb6..e88863ffb135 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S | |||
@@ -107,4 +107,7 @@ OPAL_CALL(opal_pci_mask_pe_error, OPAL_PCI_MASK_PE_ERROR); | |||
107 | OPAL_CALL(opal_set_slot_led_status, OPAL_SET_SLOT_LED_STATUS); | 107 | OPAL_CALL(opal_set_slot_led_status, OPAL_SET_SLOT_LED_STATUS); |
108 | OPAL_CALL(opal_get_epow_status, OPAL_GET_EPOW_STATUS); | 108 | OPAL_CALL(opal_get_epow_status, OPAL_GET_EPOW_STATUS); |
109 | OPAL_CALL(opal_set_system_attention_led, OPAL_SET_SYSTEM_ATTENTION_LED); | 109 | OPAL_CALL(opal_set_system_attention_led, OPAL_SET_SYSTEM_ATTENTION_LED); |
110 | OPAL_CALL(opal_pci_next_error, OPAL_PCI_NEXT_ERROR); | ||
111 | OPAL_CALL(opal_pci_poll, OPAL_PCI_POLL); | ||
110 | OPAL_CALL(opal_pci_msi_eoi, OPAL_PCI_MSI_EOI); | 112 | OPAL_CALL(opal_pci_msi_eoi, OPAL_PCI_MSI_EOI); |
113 | OPAL_CALL(opal_pci_get_phb_diag_data2, OPAL_PCI_GET_PHB_DIAG_DATA2); | ||
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 628c564ceadb..106301fd2fa5 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/of.h> | 15 | #include <linux/of.h> |
16 | #include <linux/of_platform.h> | 16 | #include <linux/of_platform.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/notifier.h> | ||
18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
19 | #include <asm/opal.h> | 20 | #include <asm/opal.h> |
20 | #include <asm/firmware.h> | 21 | #include <asm/firmware.h> |
@@ -31,6 +32,10 @@ static DEFINE_SPINLOCK(opal_write_lock); | |||
31 | extern u64 opal_mc_secondary_handler[]; | 32 | extern u64 opal_mc_secondary_handler[]; |
32 | static unsigned int *opal_irqs; | 33 | static unsigned int *opal_irqs; |
33 | static unsigned int opal_irq_count; | 34 | static unsigned int opal_irq_count; |
35 | static ATOMIC_NOTIFIER_HEAD(opal_notifier_head); | ||
36 | static DEFINE_SPINLOCK(opal_notifier_lock); | ||
37 | static uint64_t last_notified_mask = 0x0ul; | ||
38 | static atomic_t opal_notifier_hold = ATOMIC_INIT(0); | ||
34 | 39 | ||
35 | int __init early_init_dt_scan_opal(unsigned long node, | 40 | int __init early_init_dt_scan_opal(unsigned long node, |
36 | const char *uname, int depth, void *data) | 41 | const char *uname, int depth, void *data) |
@@ -95,6 +100,68 @@ static int __init opal_register_exception_handlers(void) | |||
95 | 100 | ||
96 | early_initcall(opal_register_exception_handlers); | 101 | early_initcall(opal_register_exception_handlers); |
97 | 102 | ||
103 | int opal_notifier_register(struct notifier_block *nb) | ||
104 | { | ||
105 | if (!nb) { | ||
106 | pr_warning("%s: Invalid argument (%p)\n", | ||
107 | __func__, nb); | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | |||
111 | atomic_notifier_chain_register(&opal_notifier_head, nb); | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static void opal_do_notifier(uint64_t events) | ||
116 | { | ||
117 | unsigned long flags; | ||
118 | uint64_t changed_mask; | ||
119 | |||
120 | if (atomic_read(&opal_notifier_hold)) | ||
121 | return; | ||
122 | |||
123 | spin_lock_irqsave(&opal_notifier_lock, flags); | ||
124 | changed_mask = last_notified_mask ^ events; | ||
125 | last_notified_mask = events; | ||
126 | spin_unlock_irqrestore(&opal_notifier_lock, flags); | ||
127 | |||
128 | /* | ||
129 | * We feed with the event bits and changed bits for | ||
130 | * enough information to the callback. | ||
131 | */ | ||
132 | atomic_notifier_call_chain(&opal_notifier_head, | ||
133 | events, (void *)changed_mask); | ||
134 | } | ||
135 | |||
136 | void opal_notifier_update_evt(uint64_t evt_mask, | ||
137 | uint64_t evt_val) | ||
138 | { | ||
139 | unsigned long flags; | ||
140 | |||
141 | spin_lock_irqsave(&opal_notifier_lock, flags); | ||
142 | last_notified_mask &= ~evt_mask; | ||
143 | last_notified_mask |= evt_val; | ||
144 | spin_unlock_irqrestore(&opal_notifier_lock, flags); | ||
145 | } | ||
146 | |||
147 | void opal_notifier_enable(void) | ||
148 | { | ||
149 | int64_t rc; | ||
150 | uint64_t evt = 0; | ||
151 | |||
152 | atomic_set(&opal_notifier_hold, 0); | ||
153 | |||
154 | /* Process pending events */ | ||
155 | rc = opal_poll_events(&evt); | ||
156 | if (rc == OPAL_SUCCESS && evt) | ||
157 | opal_do_notifier(evt); | ||
158 | } | ||
159 | |||
160 | void opal_notifier_disable(void) | ||
161 | { | ||
162 | atomic_set(&opal_notifier_hold, 1); | ||
163 | } | ||
164 | |||
98 | int opal_get_chars(uint32_t vtermno, char *buf, int count) | 165 | int opal_get_chars(uint32_t vtermno, char *buf, int count) |
99 | { | 166 | { |
100 | s64 len, rc; | 167 | s64 len, rc; |
@@ -297,7 +364,7 @@ static irqreturn_t opal_interrupt(int irq, void *data) | |||
297 | 364 | ||
298 | opal_handle_interrupt(virq_to_hw(irq), &events); | 365 | opal_handle_interrupt(virq_to_hw(irq), &events); |
299 | 366 | ||
300 | /* XXX TODO: Do something with the events */ | 367 | opal_do_notifier(events); |
301 | 368 | ||
302 | return IRQ_HANDLED; | 369 | return IRQ_HANDLED; |
303 | } | 370 | } |
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 9c9d15e4cdf2..49b57b9f835d 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/pci.h> | 15 | #include <linux/pci.h> |
16 | #include <linux/debugfs.h> | ||
16 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
17 | #include <linux/string.h> | 18 | #include <linux/string.h> |
18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
@@ -32,6 +33,7 @@ | |||
32 | #include <asm/iommu.h> | 33 | #include <asm/iommu.h> |
33 | #include <asm/tce.h> | 34 | #include <asm/tce.h> |
34 | #include <asm/xics.h> | 35 | #include <asm/xics.h> |
36 | #include <asm/debug.h> | ||
35 | 37 | ||
36 | #include "powernv.h" | 38 | #include "powernv.h" |
37 | #include "pci.h" | 39 | #include "pci.h" |
@@ -441,6 +443,17 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev | |||
441 | set_iommu_table_base(&pdev->dev, &pe->tce32_table); | 443 | set_iommu_table_base(&pdev->dev, &pe->tce32_table); |
442 | } | 444 | } |
443 | 445 | ||
446 | static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus) | ||
447 | { | ||
448 | struct pci_dev *dev; | ||
449 | |||
450 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
451 | set_iommu_table_base(&dev->dev, &pe->tce32_table); | ||
452 | if (dev->subordinate) | ||
453 | pnv_ioda_setup_bus_dma(pe, dev->subordinate); | ||
454 | } | ||
455 | } | ||
456 | |||
444 | static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl, | 457 | static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl, |
445 | u64 *startp, u64 *endp) | 458 | u64 *startp, u64 *endp) |
446 | { | 459 | { |
@@ -595,6 +608,12 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, | |||
595 | TCE_PCI_SWINV_PAIR; | 608 | TCE_PCI_SWINV_PAIR; |
596 | } | 609 | } |
597 | iommu_init_table(tbl, phb->hose->node); | 610 | iommu_init_table(tbl, phb->hose->node); |
611 | iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number); | ||
612 | |||
613 | if (pe->pdev) | ||
614 | set_iommu_table_base(&pe->pdev->dev, tbl); | ||
615 | else | ||
616 | pnv_ioda_setup_bus_dma(pe, pe->pbus); | ||
598 | 617 | ||
599 | return; | 618 | return; |
600 | fail: | 619 | fail: |
@@ -667,6 +686,11 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, | |||
667 | } | 686 | } |
668 | iommu_init_table(tbl, phb->hose->node); | 687 | iommu_init_table(tbl, phb->hose->node); |
669 | 688 | ||
689 | if (pe->pdev) | ||
690 | set_iommu_table_base(&pe->pdev->dev, tbl); | ||
691 | else | ||
692 | pnv_ioda_setup_bus_dma(pe, pe->pbus); | ||
693 | |||
670 | return; | 694 | return; |
671 | fail: | 695 | fail: |
672 | if (pe->tce32_seg >= 0) | 696 | if (pe->tce32_seg >= 0) |
@@ -968,11 +992,38 @@ static void pnv_pci_ioda_setup_DMA(void) | |||
968 | } | 992 | } |
969 | } | 993 | } |
970 | 994 | ||
995 | static void pnv_pci_ioda_create_dbgfs(void) | ||
996 | { | ||
997 | #ifdef CONFIG_DEBUG_FS | ||
998 | struct pci_controller *hose, *tmp; | ||
999 | struct pnv_phb *phb; | ||
1000 | char name[16]; | ||
1001 | |||
1002 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | ||
1003 | phb = hose->private_data; | ||
1004 | |||
1005 | sprintf(name, "PCI%04x", hose->global_number); | ||
1006 | phb->dbgfs = debugfs_create_dir(name, powerpc_debugfs_root); | ||
1007 | if (!phb->dbgfs) | ||
1008 | pr_warning("%s: Error on creating debugfs on PHB#%x\n", | ||
1009 | __func__, hose->global_number); | ||
1010 | } | ||
1011 | #endif /* CONFIG_DEBUG_FS */ | ||
1012 | } | ||
1013 | |||
971 | static void pnv_pci_ioda_fixup(void) | 1014 | static void pnv_pci_ioda_fixup(void) |
972 | { | 1015 | { |
973 | pnv_pci_ioda_setup_PEs(); | 1016 | pnv_pci_ioda_setup_PEs(); |
974 | pnv_pci_ioda_setup_seg(); | 1017 | pnv_pci_ioda_setup_seg(); |
975 | pnv_pci_ioda_setup_DMA(); | 1018 | pnv_pci_ioda_setup_DMA(); |
1019 | |||
1020 | pnv_pci_ioda_create_dbgfs(); | ||
1021 | |||
1022 | #ifdef CONFIG_EEH | ||
1023 | eeh_probe_mode_set(EEH_PROBE_MODE_DEV); | ||
1024 | eeh_addr_cache_build(); | ||
1025 | eeh_init(); | ||
1026 | #endif | ||
976 | } | 1027 | } |
977 | 1028 | ||
978 | /* | 1029 | /* |
@@ -1049,7 +1100,8 @@ static void pnv_pci_ioda_shutdown(struct pnv_phb *phb) | |||
1049 | OPAL_ASSERT_RESET); | 1100 | OPAL_ASSERT_RESET); |
1050 | } | 1101 | } |
1051 | 1102 | ||
1052 | void __init pnv_pci_init_ioda_phb(struct device_node *np, int ioda_type) | 1103 | void __init pnv_pci_init_ioda_phb(struct device_node *np, |
1104 | u64 hub_id, int ioda_type) | ||
1053 | { | 1105 | { |
1054 | struct pci_controller *hose; | 1106 | struct pci_controller *hose; |
1055 | static int primary = 1; | 1107 | static int primary = 1; |
@@ -1087,6 +1139,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, int ioda_type) | |||
1087 | hose->first_busno = 0; | 1139 | hose->first_busno = 0; |
1088 | hose->last_busno = 0xff; | 1140 | hose->last_busno = 0xff; |
1089 | hose->private_data = phb; | 1141 | hose->private_data = phb; |
1142 | phb->hub_id = hub_id; | ||
1090 | phb->opal_id = phb_id; | 1143 | phb->opal_id = phb_id; |
1091 | phb->type = ioda_type; | 1144 | phb->type = ioda_type; |
1092 | 1145 | ||
@@ -1172,6 +1225,9 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, int ioda_type) | |||
1172 | phb->ioda.io_size, phb->ioda.io_segsize); | 1225 | phb->ioda.io_size, phb->ioda.io_segsize); |
1173 | 1226 | ||
1174 | phb->hose->ops = &pnv_pci_ops; | 1227 | phb->hose->ops = &pnv_pci_ops; |
1228 | #ifdef CONFIG_EEH | ||
1229 | phb->eeh_ops = &ioda_eeh_ops; | ||
1230 | #endif | ||
1175 | 1231 | ||
1176 | /* Setup RID -> PE mapping function */ | 1232 | /* Setup RID -> PE mapping function */ |
1177 | phb->bdfn_to_pe = pnv_ioda_bdfn_to_pe; | 1233 | phb->bdfn_to_pe = pnv_ioda_bdfn_to_pe; |
@@ -1212,7 +1268,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, int ioda_type) | |||
1212 | 1268 | ||
1213 | void pnv_pci_init_ioda2_phb(struct device_node *np) | 1269 | void pnv_pci_init_ioda2_phb(struct device_node *np) |
1214 | { | 1270 | { |
1215 | pnv_pci_init_ioda_phb(np, PNV_PHB_IODA2); | 1271 | pnv_pci_init_ioda_phb(np, 0, PNV_PHB_IODA2); |
1216 | } | 1272 | } |
1217 | 1273 | ||
1218 | void __init pnv_pci_init_ioda_hub(struct device_node *np) | 1274 | void __init pnv_pci_init_ioda_hub(struct device_node *np) |
@@ -1235,6 +1291,6 @@ void __init pnv_pci_init_ioda_hub(struct device_node *np) | |||
1235 | for_each_child_of_node(np, phbn) { | 1291 | for_each_child_of_node(np, phbn) { |
1236 | /* Look for IODA1 PHBs */ | 1292 | /* Look for IODA1 PHBs */ |
1237 | if (of_device_is_compatible(phbn, "ibm,ioda-phb")) | 1293 | if (of_device_is_compatible(phbn, "ibm,ioda-phb")) |
1238 | pnv_pci_init_ioda_phb(phbn, PNV_PHB_IODA1); | 1294 | pnv_pci_init_ioda_phb(phbn, hub_id, PNV_PHB_IODA1); |
1239 | } | 1295 | } |
1240 | } | 1296 | } |
diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c index 92b37a0186c9..b68db6325c1b 100644 --- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c +++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c | |||
@@ -86,13 +86,16 @@ static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) { } | |||
86 | static void pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb, | 86 | static void pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb, |
87 | struct pci_dev *pdev) | 87 | struct pci_dev *pdev) |
88 | { | 88 | { |
89 | if (phb->p5ioc2.iommu_table.it_map == NULL) | 89 | if (phb->p5ioc2.iommu_table.it_map == NULL) { |
90 | iommu_init_table(&phb->p5ioc2.iommu_table, phb->hose->node); | 90 | iommu_init_table(&phb->p5ioc2.iommu_table, phb->hose->node); |
91 | iommu_register_group(&phb->p5ioc2.iommu_table, | ||
92 | pci_domain_nr(phb->hose->bus), phb->opal_id); | ||
93 | } | ||
91 | 94 | ||
92 | set_iommu_table_base(&pdev->dev, &phb->p5ioc2.iommu_table); | 95 | set_iommu_table_base(&pdev->dev, &phb->p5ioc2.iommu_table); |
93 | } | 96 | } |
94 | 97 | ||
95 | static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, | 98 | static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id, |
96 | void *tce_mem, u64 tce_size) | 99 | void *tce_mem, u64 tce_size) |
97 | { | 100 | { |
98 | struct pnv_phb *phb; | 101 | struct pnv_phb *phb; |
@@ -133,6 +136,7 @@ static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, | |||
133 | phb->hose->first_busno = 0; | 136 | phb->hose->first_busno = 0; |
134 | phb->hose->last_busno = 0xff; | 137 | phb->hose->last_busno = 0xff; |
135 | phb->hose->private_data = phb; | 138 | phb->hose->private_data = phb; |
139 | phb->hub_id = hub_id; | ||
136 | phb->opal_id = phb_id; | 140 | phb->opal_id = phb_id; |
137 | phb->type = PNV_PHB_P5IOC2; | 141 | phb->type = PNV_PHB_P5IOC2; |
138 | phb->model = PNV_PHB_MODEL_P5IOC2; | 142 | phb->model = PNV_PHB_MODEL_P5IOC2; |
@@ -226,7 +230,8 @@ void __init pnv_pci_init_p5ioc2_hub(struct device_node *np) | |||
226 | for_each_child_of_node(np, phbn) { | 230 | for_each_child_of_node(np, phbn) { |
227 | if (of_device_is_compatible(phbn, "ibm,p5ioc2-pcix") || | 231 | if (of_device_is_compatible(phbn, "ibm,p5ioc2-pcix") || |
228 | of_device_is_compatible(phbn, "ibm,p5ioc2-pciex")) { | 232 | of_device_is_compatible(phbn, "ibm,p5ioc2-pciex")) { |
229 | pnv_pci_init_p5ioc2_phb(phbn, tce_mem, tce_per_phb); | 233 | pnv_pci_init_p5ioc2_phb(phbn, hub_id, |
234 | tce_mem, tce_per_phb); | ||
230 | tce_mem += tce_per_phb; | 235 | tce_mem += tce_per_phb; |
231 | } | 236 | } |
232 | } | 237 | } |
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 277343cc6a3d..a28d3b5e6393 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <linux/io.h> | 21 | #include <linux/io.h> |
22 | #include <linux/msi.h> | 22 | #include <linux/msi.h> |
23 | #include <linux/iommu.h> | ||
23 | 24 | ||
24 | #include <asm/sections.h> | 25 | #include <asm/sections.h> |
25 | #include <asm/io.h> | 26 | #include <asm/io.h> |
@@ -32,6 +33,8 @@ | |||
32 | #include <asm/iommu.h> | 33 | #include <asm/iommu.h> |
33 | #include <asm/tce.h> | 34 | #include <asm/tce.h> |
34 | #include <asm/firmware.h> | 35 | #include <asm/firmware.h> |
36 | #include <asm/eeh_event.h> | ||
37 | #include <asm/eeh.h> | ||
35 | 38 | ||
36 | #include "powernv.h" | 39 | #include "powernv.h" |
37 | #include "pci.h" | 40 | #include "pci.h" |
@@ -202,7 +205,8 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no) | |||
202 | 205 | ||
203 | spin_lock_irqsave(&phb->lock, flags); | 206 | spin_lock_irqsave(&phb->lock, flags); |
204 | 207 | ||
205 | rc = opal_pci_get_phb_diag_data(phb->opal_id, phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE); | 208 | rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob, |
209 | PNV_PCI_DIAG_BUF_SIZE); | ||
206 | has_diag = (rc == OPAL_SUCCESS); | 210 | has_diag = (rc == OPAL_SUCCESS); |
207 | 211 | ||
208 | rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no, | 212 | rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no, |
@@ -227,43 +231,50 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no) | |||
227 | spin_unlock_irqrestore(&phb->lock, flags); | 231 | spin_unlock_irqrestore(&phb->lock, flags); |
228 | } | 232 | } |
229 | 233 | ||
230 | static void pnv_pci_config_check_eeh(struct pnv_phb *phb, struct pci_bus *bus, | 234 | static void pnv_pci_config_check_eeh(struct pnv_phb *phb, |
231 | u32 bdfn) | 235 | struct device_node *dn) |
232 | { | 236 | { |
233 | s64 rc; | 237 | s64 rc; |
234 | u8 fstate; | 238 | u8 fstate; |
235 | u16 pcierr; | 239 | u16 pcierr; |
236 | u32 pe_no; | 240 | u32 pe_no; |
237 | 241 | ||
238 | /* Get PE# if we support IODA */ | 242 | /* |
239 | pe_no = phb->bdfn_to_pe ? phb->bdfn_to_pe(phb, bus, bdfn & 0xff) : 0; | 243 | * Get the PE#. During the PCI probe stage, we might not |
244 | * setup that yet. So all ER errors should be mapped to | ||
245 | * PE#0 | ||
246 | */ | ||
247 | pe_no = PCI_DN(dn)->pe_number; | ||
248 | if (pe_no == IODA_INVALID_PE) | ||
249 | pe_no = 0; | ||
240 | 250 | ||
241 | /* Read freeze status */ | 251 | /* Read freeze status */ |
242 | rc = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, &fstate, &pcierr, | 252 | rc = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, &fstate, &pcierr, |
243 | NULL); | 253 | NULL); |
244 | if (rc) { | 254 | if (rc) { |
245 | pr_warning("PCI %d: Failed to read EEH status for PE#%d," | 255 | pr_warning("%s: Can't read EEH status (PE#%d) for " |
246 | " err %lld\n", phb->hose->global_number, pe_no, rc); | 256 | "%s, err %lld\n", |
257 | __func__, pe_no, dn->full_name, rc); | ||
247 | return; | 258 | return; |
248 | } | 259 | } |
249 | cfg_dbg(" -> EEH check, bdfn=%04x PE%d fstate=%x\n", | 260 | cfg_dbg(" -> EEH check, bdfn=%04x PE#%d fstate=%x\n", |
250 | bdfn, pe_no, fstate); | 261 | (PCI_DN(dn)->busno << 8) | (PCI_DN(dn)->devfn), |
262 | pe_no, fstate); | ||
251 | if (fstate != 0) | 263 | if (fstate != 0) |
252 | pnv_pci_handle_eeh_config(phb, pe_no); | 264 | pnv_pci_handle_eeh_config(phb, pe_no); |
253 | } | 265 | } |
254 | 266 | ||
255 | static int pnv_pci_read_config(struct pci_bus *bus, | 267 | int pnv_pci_cfg_read(struct device_node *dn, |
256 | unsigned int devfn, | 268 | int where, int size, u32 *val) |
257 | int where, int size, u32 *val) | ||
258 | { | 269 | { |
259 | struct pci_controller *hose = pci_bus_to_host(bus); | 270 | struct pci_dn *pdn = PCI_DN(dn); |
260 | struct pnv_phb *phb = hose->private_data; | 271 | struct pnv_phb *phb = pdn->phb->private_data; |
261 | u32 bdfn = (((uint64_t)bus->number) << 8) | devfn; | 272 | u32 bdfn = (pdn->busno << 8) | pdn->devfn; |
273 | #ifdef CONFIG_EEH | ||
274 | struct eeh_pe *phb_pe = NULL; | ||
275 | #endif | ||
262 | s64 rc; | 276 | s64 rc; |
263 | 277 | ||
264 | if (hose == NULL) | ||
265 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
266 | |||
267 | switch (size) { | 278 | switch (size) { |
268 | case 1: { | 279 | case 1: { |
269 | u8 v8; | 280 | u8 v8; |
@@ -287,28 +298,43 @@ static int pnv_pci_read_config(struct pci_bus *bus, | |||
287 | default: | 298 | default: |
288 | return PCIBIOS_FUNC_NOT_SUPPORTED; | 299 | return PCIBIOS_FUNC_NOT_SUPPORTED; |
289 | } | 300 | } |
290 | cfg_dbg("pnv_pci_read_config bus: %x devfn: %x +%x/%x -> %08x\n", | 301 | cfg_dbg("%s: bus: %x devfn: %x +%x/%x -> %08x\n", |
291 | bus->number, devfn, where, size, *val); | 302 | __func__, pdn->busno, pdn->devfn, where, size, *val); |
292 | 303 | ||
293 | /* Check if the PHB got frozen due to an error (no response) */ | 304 | /* |
294 | pnv_pci_config_check_eeh(phb, bus, bdfn); | 305 | * Check if the specified PE has been put into frozen |
306 | * state. On the other hand, we needn't do that while | ||
307 | * the PHB has been put into frozen state because of | ||
308 | * PHB-fatal errors. | ||
309 | */ | ||
310 | #ifdef CONFIG_EEH | ||
311 | phb_pe = eeh_phb_pe_get(pdn->phb); | ||
312 | if (phb_pe && (phb_pe->state & EEH_PE_ISOLATED)) | ||
313 | return PCIBIOS_SUCCESSFUL; | ||
314 | |||
315 | if (phb->eeh_state & PNV_EEH_STATE_ENABLED) { | ||
316 | if (*val == EEH_IO_ERROR_VALUE(size) && | ||
317 | eeh_dev_check_failure(of_node_to_eeh_dev(dn))) | ||
318 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
319 | } else { | ||
320 | pnv_pci_config_check_eeh(phb, dn); | ||
321 | } | ||
322 | #else | ||
323 | pnv_pci_config_check_eeh(phb, dn); | ||
324 | #endif | ||
295 | 325 | ||
296 | return PCIBIOS_SUCCESSFUL; | 326 | return PCIBIOS_SUCCESSFUL; |
297 | } | 327 | } |
298 | 328 | ||
299 | static int pnv_pci_write_config(struct pci_bus *bus, | 329 | int pnv_pci_cfg_write(struct device_node *dn, |
300 | unsigned int devfn, | 330 | int where, int size, u32 val) |
301 | int where, int size, u32 val) | ||
302 | { | 331 | { |
303 | struct pci_controller *hose = pci_bus_to_host(bus); | 332 | struct pci_dn *pdn = PCI_DN(dn); |
304 | struct pnv_phb *phb = hose->private_data; | 333 | struct pnv_phb *phb = pdn->phb->private_data; |
305 | u32 bdfn = (((uint64_t)bus->number) << 8) | devfn; | 334 | u32 bdfn = (pdn->busno << 8) | pdn->devfn; |
306 | |||
307 | if (hose == NULL) | ||
308 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
309 | 335 | ||
310 | cfg_dbg("pnv_pci_write_config bus: %x devfn: %x +%x/%x -> %08x\n", | 336 | cfg_dbg("%s: bus: %x devfn: %x +%x/%x -> %08x\n", |
311 | bus->number, devfn, where, size, val); | 337 | pdn->busno, pdn->devfn, where, size, val); |
312 | switch (size) { | 338 | switch (size) { |
313 | case 1: | 339 | case 1: |
314 | opal_pci_config_write_byte(phb->opal_id, bdfn, where, val); | 340 | opal_pci_config_write_byte(phb->opal_id, bdfn, where, val); |
@@ -322,14 +348,54 @@ static int pnv_pci_write_config(struct pci_bus *bus, | |||
322 | default: | 348 | default: |
323 | return PCIBIOS_FUNC_NOT_SUPPORTED; | 349 | return PCIBIOS_FUNC_NOT_SUPPORTED; |
324 | } | 350 | } |
351 | |||
325 | /* Check if the PHB got frozen due to an error (no response) */ | 352 | /* Check if the PHB got frozen due to an error (no response) */ |
326 | pnv_pci_config_check_eeh(phb, bus, bdfn); | 353 | #ifdef CONFIG_EEH |
354 | if (!(phb->eeh_state & PNV_EEH_STATE_ENABLED)) | ||
355 | pnv_pci_config_check_eeh(phb, dn); | ||
356 | #else | ||
357 | pnv_pci_config_check_eeh(phb, dn); | ||
358 | #endif | ||
327 | 359 | ||
328 | return PCIBIOS_SUCCESSFUL; | 360 | return PCIBIOS_SUCCESSFUL; |
329 | } | 361 | } |
330 | 362 | ||
363 | static int pnv_pci_read_config(struct pci_bus *bus, | ||
364 | unsigned int devfn, | ||
365 | int where, int size, u32 *val) | ||
366 | { | ||
367 | struct device_node *dn, *busdn = pci_bus_to_OF_node(bus); | ||
368 | struct pci_dn *pdn; | ||
369 | |||
370 | for (dn = busdn->child; dn; dn = dn->sibling) { | ||
371 | pdn = PCI_DN(dn); | ||
372 | if (pdn && pdn->devfn == devfn) | ||
373 | return pnv_pci_cfg_read(dn, where, size, val); | ||
374 | } | ||
375 | |||
376 | *val = 0xFFFFFFFF; | ||
377 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
378 | |||
379 | } | ||
380 | |||
381 | static int pnv_pci_write_config(struct pci_bus *bus, | ||
382 | unsigned int devfn, | ||
383 | int where, int size, u32 val) | ||
384 | { | ||
385 | struct device_node *dn, *busdn = pci_bus_to_OF_node(bus); | ||
386 | struct pci_dn *pdn; | ||
387 | |||
388 | for (dn = busdn->child; dn; dn = dn->sibling) { | ||
389 | pdn = PCI_DN(dn); | ||
390 | if (pdn && pdn->devfn == devfn) | ||
391 | return pnv_pci_cfg_write(dn, where, size, val); | ||
392 | } | ||
393 | |||
394 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
395 | } | ||
396 | |||
331 | struct pci_ops pnv_pci_ops = { | 397 | struct pci_ops pnv_pci_ops = { |
332 | .read = pnv_pci_read_config, | 398 | .read = pnv_pci_read_config, |
333 | .write = pnv_pci_write_config, | 399 | .write = pnv_pci_write_config, |
334 | }; | 400 | }; |
335 | 401 | ||
@@ -412,6 +478,7 @@ static struct iommu_table *pnv_pci_setup_bml_iommu(struct pci_controller *hose) | |||
412 | pnv_pci_setup_iommu_table(tbl, __va(be64_to_cpup(basep)), | 478 | pnv_pci_setup_iommu_table(tbl, __va(be64_to_cpup(basep)), |
413 | be32_to_cpup(sizep), 0); | 479 | be32_to_cpup(sizep), 0); |
414 | iommu_init_table(tbl, hose->node); | 480 | iommu_init_table(tbl, hose->node); |
481 | iommu_register_group(tbl, pci_domain_nr(hose->bus), 0); | ||
415 | 482 | ||
416 | /* Deal with SW invalidated TCEs when needed (BML way) */ | 483 | /* Deal with SW invalidated TCEs when needed (BML way) */ |
417 | swinvp = of_get_property(hose->dn, "linux,tce-sw-invalidate-info", | 484 | swinvp = of_get_property(hose->dn, "linux,tce-sw-invalidate-info", |
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 25d76c4df50b..d633c64e05a1 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h | |||
@@ -66,15 +66,43 @@ struct pnv_ioda_pe { | |||
66 | struct list_head list; | 66 | struct list_head list; |
67 | }; | 67 | }; |
68 | 68 | ||
69 | /* IOC dependent EEH operations */ | ||
70 | #ifdef CONFIG_EEH | ||
71 | struct pnv_eeh_ops { | ||
72 | int (*post_init)(struct pci_controller *hose); | ||
73 | int (*set_option)(struct eeh_pe *pe, int option); | ||
74 | int (*get_state)(struct eeh_pe *pe); | ||
75 | int (*reset)(struct eeh_pe *pe, int option); | ||
76 | int (*get_log)(struct eeh_pe *pe, int severity, | ||
77 | char *drv_log, unsigned long len); | ||
78 | int (*configure_bridge)(struct eeh_pe *pe); | ||
79 | int (*next_error)(struct eeh_pe **pe); | ||
80 | }; | ||
81 | |||
82 | #define PNV_EEH_STATE_ENABLED (1 << 0) /* EEH enabled */ | ||
83 | #define PNV_EEH_STATE_REMOVED (1 << 1) /* PHB removed */ | ||
84 | |||
85 | #endif /* CONFIG_EEH */ | ||
86 | |||
69 | struct pnv_phb { | 87 | struct pnv_phb { |
70 | struct pci_controller *hose; | 88 | struct pci_controller *hose; |
71 | enum pnv_phb_type type; | 89 | enum pnv_phb_type type; |
72 | enum pnv_phb_model model; | 90 | enum pnv_phb_model model; |
91 | u64 hub_id; | ||
73 | u64 opal_id; | 92 | u64 opal_id; |
74 | void __iomem *regs; | 93 | void __iomem *regs; |
75 | int initialized; | 94 | int initialized; |
76 | spinlock_t lock; | 95 | spinlock_t lock; |
77 | 96 | ||
97 | #ifdef CONFIG_EEH | ||
98 | struct pnv_eeh_ops *eeh_ops; | ||
99 | int eeh_state; | ||
100 | #endif | ||
101 | |||
102 | #ifdef CONFIG_DEBUG_FS | ||
103 | struct dentry *dbgfs; | ||
104 | #endif | ||
105 | |||
78 | #ifdef CONFIG_PCI_MSI | 106 | #ifdef CONFIG_PCI_MSI |
79 | unsigned int msi_base; | 107 | unsigned int msi_base; |
80 | unsigned int msi32_support; | 108 | unsigned int msi32_support; |
@@ -150,7 +178,14 @@ struct pnv_phb { | |||
150 | }; | 178 | }; |
151 | 179 | ||
152 | extern struct pci_ops pnv_pci_ops; | 180 | extern struct pci_ops pnv_pci_ops; |
181 | #ifdef CONFIG_EEH | ||
182 | extern struct pnv_eeh_ops ioda_eeh_ops; | ||
183 | #endif | ||
153 | 184 | ||
185 | int pnv_pci_cfg_read(struct device_node *dn, | ||
186 | int where, int size, u32 *val); | ||
187 | int pnv_pci_cfg_write(struct device_node *dn, | ||
188 | int where, int size, u32 val); | ||
154 | extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl, | 189 | extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl, |
155 | void *tce_mem, u64 tce_size, | 190 | void *tce_mem, u64 tce_size, |
156 | u64 dma_offset); | 191 | u64 dma_offset); |
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index d4459bfc92f7..84438af96c05 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c | |||
@@ -93,6 +93,8 @@ static void __noreturn pnv_restart(char *cmd) | |||
93 | { | 93 | { |
94 | long rc = OPAL_BUSY; | 94 | long rc = OPAL_BUSY; |
95 | 95 | ||
96 | opal_notifier_disable(); | ||
97 | |||
96 | while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { | 98 | while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { |
97 | rc = opal_cec_reboot(); | 99 | rc = opal_cec_reboot(); |
98 | if (rc == OPAL_BUSY_EVENT) | 100 | if (rc == OPAL_BUSY_EVENT) |
@@ -108,6 +110,8 @@ static void __noreturn pnv_power_off(void) | |||
108 | { | 110 | { |
109 | long rc = OPAL_BUSY; | 111 | long rc = OPAL_BUSY; |
110 | 112 | ||
113 | opal_notifier_disable(); | ||
114 | |||
111 | while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { | 115 | while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { |
112 | rc = opal_cec_power_down(0); | 116 | rc = opal_cec_power_down(0); |
113 | if (rc == OPAL_BUSY_EVENT) | 117 | if (rc == OPAL_BUSY_EVENT) |
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index 88c9459c3e07..89e3857af4e0 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c | |||
@@ -40,7 +40,7 @@ | |||
40 | #define DBG(fmt...) | 40 | #define DBG(fmt...) |
41 | #endif | 41 | #endif |
42 | 42 | ||
43 | static void __cpuinit pnv_smp_setup_cpu(int cpu) | 43 | static void pnv_smp_setup_cpu(int cpu) |
44 | { | 44 | { |
45 | if (cpu != boot_cpuid) | 45 | if (cpu != boot_cpuid) |
46 | xics_setup_cpu(); | 46 | xics_setup_cpu(); |
@@ -51,7 +51,7 @@ static int pnv_smp_cpu_bootable(unsigned int nr) | |||
51 | /* Special case - we inhibit secondary thread startup | 51 | /* Special case - we inhibit secondary thread startup |
52 | * during boot if the user requests it. | 52 | * during boot if the user requests it. |
53 | */ | 53 | */ |
54 | if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT)) { | 54 | if (system_state == SYSTEM_BOOTING && cpu_has_feature(CPU_FTR_SMT)) { |
55 | if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) | 55 | if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) |
56 | return 0; | 56 | return 0; |
57 | if (smt_enabled_at_boot | 57 | if (smt_enabled_at_boot |