diff options
author | Gavin Shan <shangw@linux.vnet.ibm.com> | 2013-06-20 01:20:52 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-06-20 03:05:35 -0400 |
commit | 317f06de78152e0eb0aab5881d69e4c5cdf9f1fe (patch) | |
tree | 7e3253345db6e8bab2089eee8cd268ac0c90ac9b /arch/powerpc/kernel/eeh.c | |
parent | a84f273c30500c0d5816e07232e3326a61956016 (diff) |
powerpc/eeh: Move common part to kernel directory
The patch moves the common part of EEH core into arch/powerpc/kernel
directory so that we needn't PPC_PSERIES while compiling POWERNV
platform:
* Move the EEH common part into arch/powerpc/kernel
* Move the functions for PCI hotplug from pSeries platform to
arch/powerpc/kernel/pci-hotplug.c
* Move CONFIG_EEH from arch/powerpc/platforms/pseries/Kconfig to
arch/powerpc/platforms/Kconfig
* Adjust makefile accordingly
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/eeh.c')
-rw-r--r-- | arch/powerpc/kernel/eeh.c | 942 |
1 files changed, 942 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c new file mode 100644 index 000000000000..8a8345193083 --- /dev/null +++ b/arch/powerpc/kernel/eeh.c | |||
@@ -0,0 +1,942 @@ | |||
1 | /* | ||
2 | * Copyright IBM Corporation 2001, 2005, 2006 | ||
3 | * Copyright Dave Engebretsen & Todd Inglett 2001 | ||
4 | * Copyright Linas Vepstas 2005, 2006 | ||
5 | * Copyright 2001-2012 IBM Corporation. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | * Please address comments and feedback to Linas Vepstas <linas@austin.ibm.com> | ||
22 | */ | ||
23 | |||
24 | #include <linux/delay.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/list.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/proc_fs.h> | ||
30 | #include <linux/rbtree.h> | ||
31 | #include <linux/seq_file.h> | ||
32 | #include <linux/spinlock.h> | ||
33 | #include <linux/export.h> | ||
34 | #include <linux/of.h> | ||
35 | |||
36 | #include <linux/atomic.h> | ||
37 | #include <asm/eeh.h> | ||
38 | #include <asm/eeh_event.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <asm/machdep.h> | ||
41 | #include <asm/ppc-pci.h> | ||
42 | #include <asm/rtas.h> | ||
43 | |||
44 | |||
45 | /** Overview: | ||
46 | * EEH, or "Extended Error Handling" is a PCI bridge technology for | ||
47 | * dealing with PCI bus errors that can't be dealt with within the | ||
48 | * usual PCI framework, except by check-stopping the CPU. Systems | ||
49 | * that are designed for high-availability/reliability cannot afford | ||
50 | * to crash due to a "mere" PCI error, thus the need for EEH. | ||
51 | * An EEH-capable bridge operates by converting a detected error | ||
52 | * into a "slot freeze", taking the PCI adapter off-line, making | ||
53 | * the slot behave, from the OS'es point of view, as if the slot | ||
54 | * were "empty": all reads return 0xff's and all writes are silently | ||
55 | * ignored. EEH slot isolation events can be triggered by parity | ||
56 | * errors on the address or data busses (e.g. during posted writes), | ||
57 | * which in turn might be caused by low voltage on the bus, dust, | ||
58 | * vibration, humidity, radioactivity or plain-old failed hardware. | ||
59 | * | ||
60 | * Note, however, that one of the leading causes of EEH slot | ||
61 | * freeze events are buggy device drivers, buggy device microcode, | ||
62 | * or buggy device hardware. This is because any attempt by the | ||
63 | * device to bus-master data to a memory address that is not | ||
64 | * assigned to the device will trigger a slot freeze. (The idea | ||
65 | * is to prevent devices-gone-wild from corrupting system memory). | ||
66 | * Buggy hardware/drivers will have a miserable time co-existing | ||
67 | * with EEH. | ||
68 | * | ||
69 | * Ideally, a PCI device driver, when suspecting that an isolation | ||
70 | * event has occurred (e.g. by reading 0xff's), will then ask EEH | ||
71 | * whether this is the case, and then take appropriate steps to | ||
72 | * reset the PCI slot, the PCI device, and then resume operations. | ||
73 | * However, until that day, the checking is done here, with the | ||
74 | * eeh_check_failure() routine embedded in the MMIO macros. If | ||
75 | * the slot is found to be isolated, an "EEH Event" is synthesized | ||
76 | * and sent out for processing. | ||
77 | */ | ||
78 | |||
79 | /* If a device driver keeps reading an MMIO register in an interrupt | ||
80 | * handler after a slot isolation event, it might be broken. | ||
81 | * This sets the threshold for how many read attempts we allow | ||
82 | * before printing an error message. | ||
83 | */ | ||
84 | #define EEH_MAX_FAILS 2100000 | ||
85 | |||
86 | /* Time to wait for a PCI slot to report status, in milliseconds */ | ||
87 | #define PCI_BUS_RESET_WAIT_MSEC (60*1000) | ||
88 | |||
89 | /* Platform dependent EEH operations */ | ||
90 | struct eeh_ops *eeh_ops = NULL; | ||
91 | |||
92 | int eeh_subsystem_enabled; | ||
93 | EXPORT_SYMBOL(eeh_subsystem_enabled); | ||
94 | |||
95 | /* | ||
96 | * EEH probe mode support. The intention is to support multiple | ||
97 | * platforms for EEH. Some platforms like pSeries do PCI emunation | ||
98 | * based on device tree. However, other platforms like powernv probe | ||
99 | * PCI devices from hardware. The flag is used to distinguish that. | ||
100 | * In addition, struct eeh_ops::probe would be invoked for particular | ||
101 | * OF node or PCI device so that the corresponding PE would be created | ||
102 | * there. | ||
103 | */ | ||
104 | int eeh_probe_mode; | ||
105 | |||
106 | /* Global EEH mutex */ | ||
107 | DEFINE_MUTEX(eeh_mutex); | ||
108 | |||
109 | /* Lock to avoid races due to multiple reports of an error */ | ||
110 | static DEFINE_RAW_SPINLOCK(confirm_error_lock); | ||
111 | |||
112 | /* Buffer for reporting pci register dumps. Its here in BSS, and | ||
113 | * not dynamically alloced, so that it ends up in RMO where RTAS | ||
114 | * can access it. | ||
115 | */ | ||
116 | #define EEH_PCI_REGS_LOG_LEN 4096 | ||
117 | static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN]; | ||
118 | |||
119 | /* | ||
120 | * The struct is used to maintain the EEH global statistic | ||
121 | * information. Besides, the EEH global statistics will be | ||
122 | * exported to user space through procfs | ||
123 | */ | ||
124 | struct eeh_stats { | ||
125 | u64 no_device; /* PCI device not found */ | ||
126 | u64 no_dn; /* OF node not found */ | ||
127 | u64 no_cfg_addr; /* Config address not found */ | ||
128 | u64 ignored_check; /* EEH check skipped */ | ||
129 | u64 total_mmio_ffs; /* Total EEH checks */ | ||
130 | u64 false_positives; /* Unnecessary EEH checks */ | ||
131 | u64 slot_resets; /* PE reset */ | ||
132 | }; | ||
133 | |||
134 | static struct eeh_stats eeh_stats; | ||
135 | |||
136 | #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) | ||
137 | |||
138 | /** | ||
139 | * eeh_gather_pci_data - Copy assorted PCI config space registers to buff | ||
140 | * @edev: device to report data for | ||
141 | * @buf: point to buffer in which to log | ||
142 | * @len: amount of room in buffer | ||
143 | * | ||
144 | * This routine captures assorted PCI configuration space data, | ||
145 | * and puts them into a buffer for RTAS error logging. | ||
146 | */ | ||
147 | static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) | ||
148 | { | ||
149 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
150 | struct pci_dev *dev = eeh_dev_to_pci_dev(edev); | ||
151 | u32 cfg; | ||
152 | int cap, i; | ||
153 | int n = 0; | ||
154 | |||
155 | n += scnprintf(buf+n, len-n, "%s\n", dn->full_name); | ||
156 | printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name); | ||
157 | |||
158 | eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg); | ||
159 | n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg); | ||
160 | printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg); | ||
161 | |||
162 | eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg); | ||
163 | n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); | ||
164 | printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); | ||
165 | |||
166 | if (!dev) { | ||
167 | printk(KERN_WARNING "EEH: no PCI device for this of node\n"); | ||
168 | return n; | ||
169 | } | ||
170 | |||
171 | /* Gather bridge-specific registers */ | ||
172 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { | ||
173 | eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg); | ||
174 | n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg); | ||
175 | printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); | ||
176 | |||
177 | eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg); | ||
178 | n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg); | ||
179 | printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg); | ||
180 | } | ||
181 | |||
182 | /* Dump out the PCI-X command and status regs */ | ||
183 | cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); | ||
184 | if (cap) { | ||
185 | eeh_ops->read_config(dn, cap, 4, &cfg); | ||
186 | n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg); | ||
187 | printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg); | ||
188 | |||
189 | eeh_ops->read_config(dn, cap+4, 4, &cfg); | ||
190 | n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg); | ||
191 | printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg); | ||
192 | } | ||
193 | |||
194 | /* If PCI-E capable, dump PCI-E cap 10, and the AER */ | ||
195 | cap = pci_find_capability(dev, PCI_CAP_ID_EXP); | ||
196 | if (cap) { | ||
197 | n += scnprintf(buf+n, len-n, "pci-e cap10:\n"); | ||
198 | printk(KERN_WARNING | ||
199 | "EEH: PCI-E capabilities and status follow:\n"); | ||
200 | |||
201 | for (i=0; i<=8; i++) { | ||
202 | eeh_ops->read_config(dn, cap+4*i, 4, &cfg); | ||
203 | n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); | ||
204 | printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); | ||
205 | } | ||
206 | |||
207 | cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | ||
208 | if (cap) { | ||
209 | n += scnprintf(buf+n, len-n, "pci-e AER:\n"); | ||
210 | printk(KERN_WARNING | ||
211 | "EEH: PCI-E AER capability register set follows:\n"); | ||
212 | |||
213 | for (i=0; i<14; i++) { | ||
214 | eeh_ops->read_config(dn, cap+4*i, 4, &cfg); | ||
215 | n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); | ||
216 | printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg); | ||
217 | } | ||
218 | } | ||
219 | } | ||
220 | |||
221 | return n; | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * eeh_slot_error_detail - Generate combined log including driver log and error log | ||
226 | * @pe: EEH PE | ||
227 | * @severity: temporary or permanent error log | ||
228 | * | ||
229 | * This routine should be called to generate the combined log, which | ||
230 | * is comprised of driver log and error log. The driver log is figured | ||
231 | * out from the config space of the corresponding PCI device, while | ||
232 | * the error log is fetched through platform dependent function call. | ||
233 | */ | ||
234 | void eeh_slot_error_detail(struct eeh_pe *pe, int severity) | ||
235 | { | ||
236 | size_t loglen = 0; | ||
237 | struct eeh_dev *edev; | ||
238 | |||
239 | eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); | ||
240 | eeh_ops->configure_bridge(pe); | ||
241 | eeh_pe_restore_bars(pe); | ||
242 | |||
243 | pci_regs_buf[0] = 0; | ||
244 | eeh_pe_for_each_dev(pe, edev) { | ||
245 | loglen += eeh_gather_pci_data(edev, pci_regs_buf, | ||
246 | EEH_PCI_REGS_LOG_LEN); | ||
247 | } | ||
248 | |||
249 | eeh_ops->get_log(pe, severity, pci_regs_buf, loglen); | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * eeh_token_to_phys - Convert EEH address token to phys address | ||
254 | * @token: I/O token, should be address in the form 0xA.... | ||
255 | * | ||
256 | * This routine should be called to convert virtual I/O address | ||
257 | * to physical one. | ||
258 | */ | ||
259 | static inline unsigned long eeh_token_to_phys(unsigned long token) | ||
260 | { | ||
261 | pte_t *ptep; | ||
262 | unsigned long pa; | ||
263 | |||
264 | ptep = find_linux_pte(init_mm.pgd, token); | ||
265 | if (!ptep) | ||
266 | return token; | ||
267 | pa = pte_pfn(*ptep) << PAGE_SHIFT; | ||
268 | |||
269 | return pa | (token & (PAGE_SIZE-1)); | ||
270 | } | ||
271 | |||
272 | /** | ||
273 | * eeh_dev_check_failure - Check if all 1's data is due to EEH slot freeze | ||
274 | * @edev: eeh device | ||
275 | * | ||
276 | * Check for an EEH failure for the given device node. Call this | ||
277 | * routine if the result of a read was all 0xff's and you want to | ||
278 | * find out if this is due to an EEH slot freeze. This routine | ||
279 | * will query firmware for the EEH status. | ||
280 | * | ||
281 | * Returns 0 if there has not been an EEH error; otherwise returns | ||
282 | * a non-zero value and queues up a slot isolation event notification. | ||
283 | * | ||
284 | * It is safe to call this routine in an interrupt context. | ||
285 | */ | ||
286 | int eeh_dev_check_failure(struct eeh_dev *edev) | ||
287 | { | ||
288 | int ret; | ||
289 | unsigned long flags; | ||
290 | struct device_node *dn; | ||
291 | struct pci_dev *dev; | ||
292 | struct eeh_pe *pe; | ||
293 | int rc = 0; | ||
294 | const char *location; | ||
295 | |||
296 | eeh_stats.total_mmio_ffs++; | ||
297 | |||
298 | if (!eeh_subsystem_enabled) | ||
299 | return 0; | ||
300 | |||
301 | if (!edev) { | ||
302 | eeh_stats.no_dn++; | ||
303 | return 0; | ||
304 | } | ||
305 | dn = eeh_dev_to_of_node(edev); | ||
306 | dev = eeh_dev_to_pci_dev(edev); | ||
307 | pe = edev->pe; | ||
308 | |||
309 | /* Access to IO BARs might get this far and still not want checking. */ | ||
310 | if (!pe) { | ||
311 | eeh_stats.ignored_check++; | ||
312 | pr_debug("EEH: Ignored check for %s %s\n", | ||
313 | eeh_pci_name(dev), dn->full_name); | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | if (!pe->addr && !pe->config_addr) { | ||
318 | eeh_stats.no_cfg_addr++; | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | /* If we already have a pending isolation event for this | ||
323 | * slot, we know it's bad already, we don't need to check. | ||
324 | * Do this checking under a lock; as multiple PCI devices | ||
325 | * in one slot might report errors simultaneously, and we | ||
326 | * only want one error recovery routine running. | ||
327 | */ | ||
328 | raw_spin_lock_irqsave(&confirm_error_lock, flags); | ||
329 | rc = 1; | ||
330 | if (pe->state & EEH_PE_ISOLATED) { | ||
331 | pe->check_count++; | ||
332 | if (pe->check_count % EEH_MAX_FAILS == 0) { | ||
333 | location = of_get_property(dn, "ibm,loc-code", NULL); | ||
334 | printk(KERN_ERR "EEH: %d reads ignored for recovering device at " | ||
335 | "location=%s driver=%s pci addr=%s\n", | ||
336 | pe->check_count, location, | ||
337 | eeh_driver_name(dev), eeh_pci_name(dev)); | ||
338 | printk(KERN_ERR "EEH: Might be infinite loop in %s driver\n", | ||
339 | eeh_driver_name(dev)); | ||
340 | dump_stack(); | ||
341 | } | ||
342 | goto dn_unlock; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * Now test for an EEH failure. This is VERY expensive. | ||
347 | * Note that the eeh_config_addr may be a parent device | ||
348 | * in the case of a device behind a bridge, or it may be | ||
349 | * function zero of a multi-function device. | ||
350 | * In any case they must share a common PHB. | ||
351 | */ | ||
352 | ret = eeh_ops->get_state(pe, NULL); | ||
353 | |||
354 | /* Note that config-io to empty slots may fail; | ||
355 | * they are empty when they don't have children. | ||
356 | * We will punt with the following conditions: Failure to get | ||
357 | * PE's state, EEH not support and Permanently unavailable | ||
358 | * state, PE is in good state. | ||
359 | */ | ||
360 | if ((ret < 0) || | ||
361 | (ret == EEH_STATE_NOT_SUPPORT) || | ||
362 | (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) == | ||
363 | (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) { | ||
364 | eeh_stats.false_positives++; | ||
365 | pe->false_positives++; | ||
366 | rc = 0; | ||
367 | goto dn_unlock; | ||
368 | } | ||
369 | |||
370 | eeh_stats.slot_resets++; | ||
371 | |||
372 | /* Avoid repeated reports of this failure, including problems | ||
373 | * with other functions on this device, and functions under | ||
374 | * bridges. | ||
375 | */ | ||
376 | eeh_pe_state_mark(pe, EEH_PE_ISOLATED); | ||
377 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); | ||
378 | |||
379 | eeh_send_failure_event(pe); | ||
380 | |||
381 | /* Most EEH events are due to device driver bugs. Having | ||
382 | * a stack trace will help the device-driver authors figure | ||
383 | * out what happened. So print that out. | ||
384 | */ | ||
385 | WARN(1, "EEH: failure detected\n"); | ||
386 | return 1; | ||
387 | |||
388 | dn_unlock: | ||
389 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); | ||
390 | return rc; | ||
391 | } | ||
392 | |||
393 | EXPORT_SYMBOL_GPL(eeh_dev_check_failure); | ||
394 | |||
395 | /** | ||
396 | * eeh_check_failure - Check if all 1's data is due to EEH slot freeze | ||
397 | * @token: I/O token, should be address in the form 0xA.... | ||
398 | * @val: value, should be all 1's (XXX why do we need this arg??) | ||
399 | * | ||
400 | * Check for an EEH failure at the given token address. Call this | ||
401 | * routine if the result of a read was all 0xff's and you want to | ||
402 | * find out if this is due to an EEH slot freeze event. This routine | ||
403 | * will query firmware for the EEH status. | ||
404 | * | ||
405 | * Note this routine is safe to call in an interrupt context. | ||
406 | */ | ||
407 | unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) | ||
408 | { | ||
409 | unsigned long addr; | ||
410 | struct eeh_dev *edev; | ||
411 | |||
412 | /* Finding the phys addr + pci device; this is pretty quick. */ | ||
413 | addr = eeh_token_to_phys((unsigned long __force) token); | ||
414 | edev = eeh_addr_cache_get_dev(addr); | ||
415 | if (!edev) { | ||
416 | eeh_stats.no_device++; | ||
417 | return val; | ||
418 | } | ||
419 | |||
420 | eeh_dev_check_failure(edev); | ||
421 | |||
422 | pci_dev_put(eeh_dev_to_pci_dev(edev)); | ||
423 | return val; | ||
424 | } | ||
425 | |||
426 | EXPORT_SYMBOL(eeh_check_failure); | ||
427 | |||
428 | |||
429 | /** | ||
430 | * eeh_pci_enable - Enable MMIO or DMA transfers for this slot | ||
431 | * @pe: EEH PE | ||
432 | * | ||
433 | * This routine should be called to reenable frozen MMIO or DMA | ||
434 | * so that it would work correctly again. It's useful while doing | ||
435 | * recovery or log collection on the indicated device. | ||
436 | */ | ||
437 | int eeh_pci_enable(struct eeh_pe *pe, int function) | ||
438 | { | ||
439 | int rc; | ||
440 | |||
441 | rc = eeh_ops->set_option(pe, function); | ||
442 | if (rc) | ||
443 | pr_warning("%s: Unexpected state change %d on PHB#%d-PE#%x, err=%d\n", | ||
444 | __func__, function, pe->phb->global_number, pe->addr, rc); | ||
445 | |||
446 | rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); | ||
447 | if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) && | ||
448 | (function == EEH_OPT_THAW_MMIO)) | ||
449 | return 0; | ||
450 | |||
451 | return rc; | ||
452 | } | ||
453 | |||
454 | /** | ||
455 | * pcibios_set_pcie_slot_reset - Set PCI-E reset state | ||
456 | * @dev: pci device struct | ||
457 | * @state: reset state to enter | ||
458 | * | ||
459 | * Return value: | ||
460 | * 0 if success | ||
461 | */ | ||
462 | int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) | ||
463 | { | ||
464 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); | ||
465 | struct eeh_pe *pe = edev->pe; | ||
466 | |||
467 | if (!pe) { | ||
468 | pr_err("%s: No PE found on PCI device %s\n", | ||
469 | __func__, pci_name(dev)); | ||
470 | return -EINVAL; | ||
471 | } | ||
472 | |||
473 | switch (state) { | ||
474 | case pcie_deassert_reset: | ||
475 | eeh_ops->reset(pe, EEH_RESET_DEACTIVATE); | ||
476 | break; | ||
477 | case pcie_hot_reset: | ||
478 | eeh_ops->reset(pe, EEH_RESET_HOT); | ||
479 | break; | ||
480 | case pcie_warm_reset: | ||
481 | eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); | ||
482 | break; | ||
483 | default: | ||
484 | return -EINVAL; | ||
485 | }; | ||
486 | |||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | /** | ||
491 | * eeh_set_pe_freset - Check the required reset for the indicated device | ||
492 | * @data: EEH device | ||
493 | * @flag: return value | ||
494 | * | ||
495 | * Each device might have its preferred reset type: fundamental or | ||
496 | * hot reset. The routine is used to collected the information for | ||
497 | * the indicated device and its children so that the bunch of the | ||
498 | * devices could be reset properly. | ||
499 | */ | ||
500 | static void *eeh_set_dev_freset(void *data, void *flag) | ||
501 | { | ||
502 | struct pci_dev *dev; | ||
503 | unsigned int *freset = (unsigned int *)flag; | ||
504 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
505 | |||
506 | dev = eeh_dev_to_pci_dev(edev); | ||
507 | if (dev) | ||
508 | *freset |= dev->needs_freset; | ||
509 | |||
510 | return NULL; | ||
511 | } | ||
512 | |||
513 | /** | ||
514 | * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second | ||
515 | * @pe: EEH PE | ||
516 | * | ||
517 | * Assert the PCI #RST line for 1/4 second. | ||
518 | */ | ||
519 | static void eeh_reset_pe_once(struct eeh_pe *pe) | ||
520 | { | ||
521 | unsigned int freset = 0; | ||
522 | |||
523 | /* Determine type of EEH reset required for | ||
524 | * Partitionable Endpoint, a hot-reset (1) | ||
525 | * or a fundamental reset (3). | ||
526 | * A fundamental reset required by any device under | ||
527 | * Partitionable Endpoint trumps hot-reset. | ||
528 | */ | ||
529 | eeh_pe_dev_traverse(pe, eeh_set_dev_freset, &freset); | ||
530 | |||
531 | if (freset) | ||
532 | eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); | ||
533 | else | ||
534 | eeh_ops->reset(pe, EEH_RESET_HOT); | ||
535 | |||
536 | /* The PCI bus requires that the reset be held high for at least | ||
537 | * a 100 milliseconds. We wait a bit longer 'just in case'. | ||
538 | */ | ||
539 | #define PCI_BUS_RST_HOLD_TIME_MSEC 250 | ||
540 | msleep(PCI_BUS_RST_HOLD_TIME_MSEC); | ||
541 | |||
542 | /* We might get hit with another EEH freeze as soon as the | ||
543 | * pci slot reset line is dropped. Make sure we don't miss | ||
544 | * these, and clear the flag now. | ||
545 | */ | ||
546 | eeh_pe_state_clear(pe, EEH_PE_ISOLATED); | ||
547 | |||
548 | eeh_ops->reset(pe, EEH_RESET_DEACTIVATE); | ||
549 | |||
550 | /* After a PCI slot has been reset, the PCI Express spec requires | ||
551 | * a 1.5 second idle time for the bus to stabilize, before starting | ||
552 | * up traffic. | ||
553 | */ | ||
554 | #define PCI_BUS_SETTLE_TIME_MSEC 1800 | ||
555 | msleep(PCI_BUS_SETTLE_TIME_MSEC); | ||
556 | } | ||
557 | |||
558 | /** | ||
559 | * eeh_reset_pe - Reset the indicated PE | ||
560 | * @pe: EEH PE | ||
561 | * | ||
562 | * This routine should be called to reset indicated device, including | ||
563 | * PE. A PE might include multiple PCI devices and sometimes PCI bridges | ||
564 | * might be involved as well. | ||
565 | */ | ||
566 | int eeh_reset_pe(struct eeh_pe *pe) | ||
567 | { | ||
568 | int i, rc; | ||
569 | |||
570 | /* Take three shots at resetting the bus */ | ||
571 | for (i=0; i<3; i++) { | ||
572 | eeh_reset_pe_once(pe); | ||
573 | |||
574 | rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); | ||
575 | if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) | ||
576 | return 0; | ||
577 | |||
578 | if (rc < 0) { | ||
579 | pr_err("%s: Unrecoverable slot failure on PHB#%d-PE#%x", | ||
580 | __func__, pe->phb->global_number, pe->addr); | ||
581 | return -1; | ||
582 | } | ||
583 | pr_err("EEH: bus reset %d failed on PHB#%d-PE#%x, rc=%d\n", | ||
584 | i+1, pe->phb->global_number, pe->addr, rc); | ||
585 | } | ||
586 | |||
587 | return -1; | ||
588 | } | ||
589 | |||
590 | /** | ||
591 | * eeh_save_bars - Save device bars | ||
592 | * @edev: PCI device associated EEH device | ||
593 | * | ||
594 | * Save the values of the device bars. Unlike the restore | ||
595 | * routine, this routine is *not* recursive. This is because | ||
596 | * PCI devices are added individually; but, for the restore, | ||
597 | * an entire slot is reset at a time. | ||
598 | */ | ||
599 | void eeh_save_bars(struct eeh_dev *edev) | ||
600 | { | ||
601 | int i; | ||
602 | struct device_node *dn; | ||
603 | |||
604 | if (!edev) | ||
605 | return; | ||
606 | dn = eeh_dev_to_of_node(edev); | ||
607 | |||
608 | for (i = 0; i < 16; i++) | ||
609 | eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]); | ||
610 | } | ||
611 | |||
612 | /** | ||
613 | * eeh_ops_register - Register platform dependent EEH operations | ||
614 | * @ops: platform dependent EEH operations | ||
615 | * | ||
616 | * Register the platform dependent EEH operation callback | ||
617 | * functions. The platform should call this function before | ||
618 | * any other EEH operations. | ||
619 | */ | ||
620 | int __init eeh_ops_register(struct eeh_ops *ops) | ||
621 | { | ||
622 | if (!ops->name) { | ||
623 | pr_warning("%s: Invalid EEH ops name for %p\n", | ||
624 | __func__, ops); | ||
625 | return -EINVAL; | ||
626 | } | ||
627 | |||
628 | if (eeh_ops && eeh_ops != ops) { | ||
629 | pr_warning("%s: EEH ops of platform %s already existing (%s)\n", | ||
630 | __func__, eeh_ops->name, ops->name); | ||
631 | return -EEXIST; | ||
632 | } | ||
633 | |||
634 | eeh_ops = ops; | ||
635 | |||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | /** | ||
640 | * eeh_ops_unregister - Unreigster platform dependent EEH operations | ||
641 | * @name: name of EEH platform operations | ||
642 | * | ||
643 | * Unregister the platform dependent EEH operation callback | ||
644 | * functions. | ||
645 | */ | ||
646 | int __exit eeh_ops_unregister(const char *name) | ||
647 | { | ||
648 | if (!name || !strlen(name)) { | ||
649 | pr_warning("%s: Invalid EEH ops name\n", | ||
650 | __func__); | ||
651 | return -EINVAL; | ||
652 | } | ||
653 | |||
654 | if (eeh_ops && !strcmp(eeh_ops->name, name)) { | ||
655 | eeh_ops = NULL; | ||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | return -EEXIST; | ||
660 | } | ||
661 | |||
662 | /** | ||
663 | * eeh_init - EEH initialization | ||
664 | * | ||
665 | * Initialize EEH by trying to enable it for all of the adapters in the system. | ||
666 | * As a side effect we can determine here if eeh is supported at all. | ||
667 | * Note that we leave EEH on so failed config cycles won't cause a machine | ||
668 | * check. If a user turns off EEH for a particular adapter they are really | ||
669 | * telling Linux to ignore errors. Some hardware (e.g. POWER5) won't | ||
670 | * grant access to a slot if EEH isn't enabled, and so we always enable | ||
671 | * EEH for all slots/all devices. | ||
672 | * | ||
673 | * The eeh-force-off option disables EEH checking globally, for all slots. | ||
674 | * Even if force-off is set, the EEH hardware is still enabled, so that | ||
675 | * newer systems can boot. | ||
676 | */ | ||
677 | static int __init eeh_init(void) | ||
678 | { | ||
679 | struct pci_controller *hose, *tmp; | ||
680 | struct device_node *phb; | ||
681 | int ret; | ||
682 | |||
683 | /* call platform initialization function */ | ||
684 | if (!eeh_ops) { | ||
685 | pr_warning("%s: Platform EEH operation not found\n", | ||
686 | __func__); | ||
687 | return -EEXIST; | ||
688 | } else if ((ret = eeh_ops->init())) { | ||
689 | pr_warning("%s: Failed to call platform init function (%d)\n", | ||
690 | __func__, ret); | ||
691 | return ret; | ||
692 | } | ||
693 | |||
694 | raw_spin_lock_init(&confirm_error_lock); | ||
695 | |||
696 | /* Enable EEH for all adapters */ | ||
697 | if (eeh_probe_mode_devtree()) { | ||
698 | list_for_each_entry_safe(hose, tmp, | ||
699 | &hose_list, list_node) { | ||
700 | phb = hose->dn; | ||
701 | traverse_pci_devices(phb, eeh_ops->of_probe, NULL); | ||
702 | } | ||
703 | } | ||
704 | |||
705 | if (eeh_subsystem_enabled) | ||
706 | pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); | ||
707 | else | ||
708 | pr_warning("EEH: No capable adapters found\n"); | ||
709 | |||
710 | return ret; | ||
711 | } | ||
712 | |||
713 | core_initcall_sync(eeh_init); | ||
714 | |||
715 | /** | ||
716 | * eeh_add_device_early - Enable EEH for the indicated device_node | ||
717 | * @dn: device node for which to set up EEH | ||
718 | * | ||
719 | * This routine must be used to perform EEH initialization for PCI | ||
720 | * devices that were added after system boot (e.g. hotplug, dlpar). | ||
721 | * This routine must be called before any i/o is performed to the | ||
722 | * adapter (inluding any config-space i/o). | ||
723 | * Whether this actually enables EEH or not for this device depends | ||
724 | * on the CEC architecture, type of the device, on earlier boot | ||
725 | * command-line arguments & etc. | ||
726 | */ | ||
727 | static void eeh_add_device_early(struct device_node *dn) | ||
728 | { | ||
729 | struct pci_controller *phb; | ||
730 | |||
731 | if (!of_node_to_eeh_dev(dn)) | ||
732 | return; | ||
733 | phb = of_node_to_eeh_dev(dn)->phb; | ||
734 | |||
735 | /* USB Bus children of PCI devices will not have BUID's */ | ||
736 | if (NULL == phb || 0 == phb->buid) | ||
737 | return; | ||
738 | |||
739 | /* FIXME: hotplug support on POWERNV */ | ||
740 | eeh_ops->of_probe(dn, NULL); | ||
741 | } | ||
742 | |||
743 | /** | ||
744 | * eeh_add_device_tree_early - Enable EEH for the indicated device | ||
745 | * @dn: device node | ||
746 | * | ||
747 | * This routine must be used to perform EEH initialization for the | ||
748 | * indicated PCI device that was added after system boot (e.g. | ||
749 | * hotplug, dlpar). | ||
750 | */ | ||
751 | void eeh_add_device_tree_early(struct device_node *dn) | ||
752 | { | ||
753 | struct device_node *sib; | ||
754 | |||
755 | for_each_child_of_node(dn, sib) | ||
756 | eeh_add_device_tree_early(sib); | ||
757 | eeh_add_device_early(dn); | ||
758 | } | ||
759 | EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); | ||
760 | |||
761 | /** | ||
762 | * eeh_add_device_late - Perform EEH initialization for the indicated pci device | ||
763 | * @dev: pci device for which to set up EEH | ||
764 | * | ||
765 | * This routine must be used to complete EEH initialization for PCI | ||
766 | * devices that were added after system boot (e.g. hotplug, dlpar). | ||
767 | */ | ||
768 | static void eeh_add_device_late(struct pci_dev *dev) | ||
769 | { | ||
770 | struct device_node *dn; | ||
771 | struct eeh_dev *edev; | ||
772 | |||
773 | if (!dev || !eeh_subsystem_enabled) | ||
774 | return; | ||
775 | |||
776 | pr_debug("EEH: Adding device %s\n", pci_name(dev)); | ||
777 | |||
778 | dn = pci_device_to_OF_node(dev); | ||
779 | edev = of_node_to_eeh_dev(dn); | ||
780 | if (edev->pdev == dev) { | ||
781 | pr_debug("EEH: Already referenced !\n"); | ||
782 | return; | ||
783 | } | ||
784 | WARN_ON(edev->pdev); | ||
785 | |||
786 | pci_dev_get(dev); | ||
787 | edev->pdev = dev; | ||
788 | dev->dev.archdata.edev = edev; | ||
789 | |||
790 | eeh_addr_cache_insert_dev(dev); | ||
791 | } | ||
792 | |||
793 | /** | ||
794 | * eeh_add_device_tree_late - Perform EEH initialization for the indicated PCI bus | ||
795 | * @bus: PCI bus | ||
796 | * | ||
797 | * This routine must be used to perform EEH initialization for PCI | ||
798 | * devices which are attached to the indicated PCI bus. The PCI bus | ||
799 | * is added after system boot through hotplug or dlpar. | ||
800 | */ | ||
801 | void eeh_add_device_tree_late(struct pci_bus *bus) | ||
802 | { | ||
803 | struct pci_dev *dev; | ||
804 | |||
805 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
806 | eeh_add_device_late(dev); | ||
807 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
808 | struct pci_bus *subbus = dev->subordinate; | ||
809 | if (subbus) | ||
810 | eeh_add_device_tree_late(subbus); | ||
811 | } | ||
812 | } | ||
813 | } | ||
814 | EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); | ||
815 | |||
816 | /** | ||
817 | * eeh_add_sysfs_files - Add EEH sysfs files for the indicated PCI bus | ||
818 | * @bus: PCI bus | ||
819 | * | ||
820 | * This routine must be used to add EEH sysfs files for PCI | ||
821 | * devices which are attached to the indicated PCI bus. The PCI bus | ||
822 | * is added after system boot through hotplug or dlpar. | ||
823 | */ | ||
824 | void eeh_add_sysfs_files(struct pci_bus *bus) | ||
825 | { | ||
826 | struct pci_dev *dev; | ||
827 | |||
828 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
829 | eeh_sysfs_add_device(dev); | ||
830 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
831 | struct pci_bus *subbus = dev->subordinate; | ||
832 | if (subbus) | ||
833 | eeh_add_sysfs_files(subbus); | ||
834 | } | ||
835 | } | ||
836 | } | ||
837 | EXPORT_SYMBOL_GPL(eeh_add_sysfs_files); | ||
838 | |||
839 | /** | ||
840 | * eeh_remove_device - Undo EEH setup for the indicated pci device | ||
841 | * @dev: pci device to be removed | ||
842 | * @purge_pe: remove the PE or not | ||
843 | * | ||
844 | * This routine should be called when a device is removed from | ||
845 | * a running system (e.g. by hotplug or dlpar). It unregisters | ||
846 | * the PCI device from the EEH subsystem. I/O errors affecting | ||
847 | * this device will no longer be detected after this call; thus, | ||
848 | * i/o errors affecting this slot may leave this device unusable. | ||
849 | */ | ||
850 | static void eeh_remove_device(struct pci_dev *dev, int purge_pe) | ||
851 | { | ||
852 | struct eeh_dev *edev; | ||
853 | |||
854 | if (!dev || !eeh_subsystem_enabled) | ||
855 | return; | ||
856 | edev = pci_dev_to_eeh_dev(dev); | ||
857 | |||
858 | /* Unregister the device with the EEH/PCI address search system */ | ||
859 | pr_debug("EEH: Removing device %s\n", pci_name(dev)); | ||
860 | |||
861 | if (!edev || !edev->pdev) { | ||
862 | pr_debug("EEH: Not referenced !\n"); | ||
863 | return; | ||
864 | } | ||
865 | edev->pdev = NULL; | ||
866 | dev->dev.archdata.edev = NULL; | ||
867 | pci_dev_put(dev); | ||
868 | |||
869 | eeh_rmv_from_parent_pe(edev, purge_pe); | ||
870 | eeh_addr_cache_rmv_dev(dev); | ||
871 | eeh_sysfs_remove_device(dev); | ||
872 | } | ||
873 | |||
874 | /** | ||
875 | * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device | ||
876 | * @dev: PCI device | ||
877 | * @purge_pe: remove the corresponding PE or not | ||
878 | * | ||
879 | * This routine must be called when a device is removed from the | ||
880 | * running system through hotplug or dlpar. The corresponding | ||
881 | * PCI address cache will be removed. | ||
882 | */ | ||
883 | void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe) | ||
884 | { | ||
885 | struct pci_bus *bus = dev->subordinate; | ||
886 | struct pci_dev *child, *tmp; | ||
887 | |||
888 | eeh_remove_device(dev, purge_pe); | ||
889 | |||
890 | if (bus && dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
891 | list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) | ||
892 | eeh_remove_bus_device(child, purge_pe); | ||
893 | } | ||
894 | } | ||
895 | EXPORT_SYMBOL_GPL(eeh_remove_bus_device); | ||
896 | |||
897 | static int proc_eeh_show(struct seq_file *m, void *v) | ||
898 | { | ||
899 | if (0 == eeh_subsystem_enabled) { | ||
900 | seq_printf(m, "EEH Subsystem is globally disabled\n"); | ||
901 | seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs); | ||
902 | } else { | ||
903 | seq_printf(m, "EEH Subsystem is enabled\n"); | ||
904 | seq_printf(m, | ||
905 | "no device=%llu\n" | ||
906 | "no device node=%llu\n" | ||
907 | "no config address=%llu\n" | ||
908 | "check not wanted=%llu\n" | ||
909 | "eeh_total_mmio_ffs=%llu\n" | ||
910 | "eeh_false_positives=%llu\n" | ||
911 | "eeh_slot_resets=%llu\n", | ||
912 | eeh_stats.no_device, | ||
913 | eeh_stats.no_dn, | ||
914 | eeh_stats.no_cfg_addr, | ||
915 | eeh_stats.ignored_check, | ||
916 | eeh_stats.total_mmio_ffs, | ||
917 | eeh_stats.false_positives, | ||
918 | eeh_stats.slot_resets); | ||
919 | } | ||
920 | |||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | static int proc_eeh_open(struct inode *inode, struct file *file) | ||
925 | { | ||
926 | return single_open(file, proc_eeh_show, NULL); | ||
927 | } | ||
928 | |||
929 | static const struct file_operations proc_eeh_operations = { | ||
930 | .open = proc_eeh_open, | ||
931 | .read = seq_read, | ||
932 | .llseek = seq_lseek, | ||
933 | .release = single_release, | ||
934 | }; | ||
935 | |||
936 | static int __init eeh_init_proc(void) | ||
937 | { | ||
938 | if (machine_is(pseries)) | ||
939 | proc_create("powerpc/eeh", 0, NULL, &proc_eeh_operations); | ||
940 | return 0; | ||
941 | } | ||
942 | __initcall(eeh_init_proc); | ||