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/platforms/pseries | |
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/platforms/pseries')
-rw-r--r-- | arch/powerpc/platforms/pseries/Kconfig | 5 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/Makefile | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh.c | 942 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_cache.c | 319 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_dev.c | 112 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_driver.c | 552 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_event.c | 142 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_pe.c | 653 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_sysfs.c | 75 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pci_dlpar.c | 85 |
10 files changed, 1 insertions, 2888 deletions
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 4459eff7a75a..1bd3399146ed 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig | |||
@@ -33,11 +33,6 @@ config PPC_SPLPAR | |||
33 | processors, that is, which share physical processors between | 33 | processors, that is, which share physical processors between |
34 | two or more partitions. | 34 | two or more partitions. |
35 | 35 | ||
36 | config EEH | ||
37 | bool | ||
38 | depends on PPC_PSERIES && PCI | ||
39 | default y | ||
40 | |||
41 | config PSERIES_MSI | 36 | config PSERIES_MSI |
42 | bool | 37 | bool |
43 | depends on PCI_MSI && EEH | 38 | depends on PCI_MSI && EEH |
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 53866e537a92..8ae010381316 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
@@ -6,9 +6,7 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ | |||
6 | firmware.o power.o dlpar.o mobility.o | 6 | firmware.o power.o dlpar.o mobility.o |
7 | obj-$(CONFIG_SMP) += smp.o | 7 | obj-$(CONFIG_SMP) += smp.o |
8 | obj-$(CONFIG_SCANLOG) += scanlog.o | 8 | obj-$(CONFIG_SCANLOG) += scanlog.o |
9 | obj-$(CONFIG_EEH) += eeh.o eeh_pe.o eeh_dev.o eeh_cache.o \ | 9 | obj-$(CONFIG_EEH) += eeh_pseries.o |
10 | eeh_driver.o eeh_event.o eeh_sysfs.o \ | ||
11 | eeh_pseries.o | ||
12 | obj-$(CONFIG_KEXEC) += kexec.o | 10 | obj-$(CONFIG_KEXEC) += kexec.o |
13 | obj-$(CONFIG_PCI) += pci.o pci_dlpar.o | 11 | obj-$(CONFIG_PCI) += pci.o pci_dlpar.o |
14 | obj-$(CONFIG_PSERIES_MSI) += msi.o | 12 | obj-$(CONFIG_PSERIES_MSI) += msi.o |
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c deleted file mode 100644 index 8a8345193083..000000000000 --- a/arch/powerpc/platforms/pseries/eeh.c +++ /dev/null | |||
@@ -1,942 +0,0 @@ | |||
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); | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c deleted file mode 100644 index 5a4c87903057..000000000000 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ /dev/null | |||
@@ -1,319 +0,0 @@ | |||
1 | /* | ||
2 | * PCI address cache; allows the lookup of PCI devices based on I/O address | ||
3 | * | ||
4 | * Copyright IBM Corporation 2004 | ||
5 | * Copyright Linas Vepstas <linas@austin.ibm.com> 2004 | ||
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 | |||
22 | #include <linux/list.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/rbtree.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/atomic.h> | ||
28 | #include <asm/pci-bridge.h> | ||
29 | #include <asm/ppc-pci.h> | ||
30 | |||
31 | |||
32 | /** | ||
33 | * The pci address cache subsystem. This subsystem places | ||
34 | * PCI device address resources into a red-black tree, sorted | ||
35 | * according to the address range, so that given only an i/o | ||
36 | * address, the corresponding PCI device can be **quickly** | ||
37 | * found. It is safe to perform an address lookup in an interrupt | ||
38 | * context; this ability is an important feature. | ||
39 | * | ||
40 | * Currently, the only customer of this code is the EEH subsystem; | ||
41 | * thus, this code has been somewhat tailored to suit EEH better. | ||
42 | * In particular, the cache does *not* hold the addresses of devices | ||
43 | * for which EEH is not enabled. | ||
44 | * | ||
45 | * (Implementation Note: The RB tree seems to be better/faster | ||
46 | * than any hash algo I could think of for this problem, even | ||
47 | * with the penalty of slow pointer chases for d-cache misses). | ||
48 | */ | ||
49 | struct pci_io_addr_range { | ||
50 | struct rb_node rb_node; | ||
51 | unsigned long addr_lo; | ||
52 | unsigned long addr_hi; | ||
53 | struct eeh_dev *edev; | ||
54 | struct pci_dev *pcidev; | ||
55 | unsigned int flags; | ||
56 | }; | ||
57 | |||
58 | static struct pci_io_addr_cache { | ||
59 | struct rb_root rb_root; | ||
60 | spinlock_t piar_lock; | ||
61 | } pci_io_addr_cache_root; | ||
62 | |||
63 | static inline struct eeh_dev *__eeh_addr_cache_get_device(unsigned long addr) | ||
64 | { | ||
65 | struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; | ||
66 | |||
67 | while (n) { | ||
68 | struct pci_io_addr_range *piar; | ||
69 | piar = rb_entry(n, struct pci_io_addr_range, rb_node); | ||
70 | |||
71 | if (addr < piar->addr_lo) { | ||
72 | n = n->rb_left; | ||
73 | } else { | ||
74 | if (addr > piar->addr_hi) { | ||
75 | n = n->rb_right; | ||
76 | } else { | ||
77 | pci_dev_get(piar->pcidev); | ||
78 | return piar->edev; | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | return NULL; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * eeh_addr_cache_get_dev - Get device, given only address | ||
88 | * @addr: mmio (PIO) phys address or i/o port number | ||
89 | * | ||
90 | * Given an mmio phys address, or a port number, find a pci device | ||
91 | * that implements this address. Be sure to pci_dev_put the device | ||
92 | * when finished. I/O port numbers are assumed to be offset | ||
93 | * from zero (that is, they do *not* have pci_io_addr added in). | ||
94 | * It is safe to call this function within an interrupt. | ||
95 | */ | ||
96 | struct eeh_dev *eeh_addr_cache_get_dev(unsigned long addr) | ||
97 | { | ||
98 | struct eeh_dev *edev; | ||
99 | unsigned long flags; | ||
100 | |||
101 | spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); | ||
102 | edev = __eeh_addr_cache_get_device(addr); | ||
103 | spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); | ||
104 | return edev; | ||
105 | } | ||
106 | |||
107 | #ifdef DEBUG | ||
108 | /* | ||
109 | * Handy-dandy debug print routine, does nothing more | ||
110 | * than print out the contents of our addr cache. | ||
111 | */ | ||
112 | static void eeh_addr_cache_print(struct pci_io_addr_cache *cache) | ||
113 | { | ||
114 | struct rb_node *n; | ||
115 | int cnt = 0; | ||
116 | |||
117 | n = rb_first(&cache->rb_root); | ||
118 | while (n) { | ||
119 | struct pci_io_addr_range *piar; | ||
120 | piar = rb_entry(n, struct pci_io_addr_range, rb_node); | ||
121 | pr_debug("PCI: %s addr range %d [%lx-%lx]: %s\n", | ||
122 | (piar->flags & IORESOURCE_IO) ? "i/o" : "mem", cnt, | ||
123 | piar->addr_lo, piar->addr_hi, pci_name(piar->pcidev)); | ||
124 | cnt++; | ||
125 | n = rb_next(n); | ||
126 | } | ||
127 | } | ||
128 | #endif | ||
129 | |||
130 | /* Insert address range into the rb tree. */ | ||
131 | static struct pci_io_addr_range * | ||
132 | eeh_addr_cache_insert(struct pci_dev *dev, unsigned long alo, | ||
133 | unsigned long ahi, unsigned int flags) | ||
134 | { | ||
135 | struct rb_node **p = &pci_io_addr_cache_root.rb_root.rb_node; | ||
136 | struct rb_node *parent = NULL; | ||
137 | struct pci_io_addr_range *piar; | ||
138 | |||
139 | /* Walk tree, find a place to insert into tree */ | ||
140 | while (*p) { | ||
141 | parent = *p; | ||
142 | piar = rb_entry(parent, struct pci_io_addr_range, rb_node); | ||
143 | if (ahi < piar->addr_lo) { | ||
144 | p = &parent->rb_left; | ||
145 | } else if (alo > piar->addr_hi) { | ||
146 | p = &parent->rb_right; | ||
147 | } else { | ||
148 | if (dev != piar->pcidev || | ||
149 | alo != piar->addr_lo || ahi != piar->addr_hi) { | ||
150 | pr_warning("PIAR: overlapping address range\n"); | ||
151 | } | ||
152 | return piar; | ||
153 | } | ||
154 | } | ||
155 | piar = kzalloc(sizeof(struct pci_io_addr_range), GFP_ATOMIC); | ||
156 | if (!piar) | ||
157 | return NULL; | ||
158 | |||
159 | pci_dev_get(dev); | ||
160 | piar->addr_lo = alo; | ||
161 | piar->addr_hi = ahi; | ||
162 | piar->edev = pci_dev_to_eeh_dev(dev); | ||
163 | piar->pcidev = dev; | ||
164 | piar->flags = flags; | ||
165 | |||
166 | #ifdef DEBUG | ||
167 | pr_debug("PIAR: insert range=[%lx:%lx] dev=%s\n", | ||
168 | alo, ahi, pci_name(dev)); | ||
169 | #endif | ||
170 | |||
171 | rb_link_node(&piar->rb_node, parent, p); | ||
172 | rb_insert_color(&piar->rb_node, &pci_io_addr_cache_root.rb_root); | ||
173 | |||
174 | return piar; | ||
175 | } | ||
176 | |||
177 | static void __eeh_addr_cache_insert_dev(struct pci_dev *dev) | ||
178 | { | ||
179 | struct device_node *dn; | ||
180 | struct eeh_dev *edev; | ||
181 | int i; | ||
182 | |||
183 | dn = pci_device_to_OF_node(dev); | ||
184 | if (!dn) { | ||
185 | pr_warning("PCI: no pci dn found for dev=%s\n", pci_name(dev)); | ||
186 | return; | ||
187 | } | ||
188 | |||
189 | edev = of_node_to_eeh_dev(dn); | ||
190 | if (!edev) { | ||
191 | pr_warning("PCI: no EEH dev found for dn=%s\n", | ||
192 | dn->full_name); | ||
193 | return; | ||
194 | } | ||
195 | |||
196 | /* Skip any devices for which EEH is not enabled. */ | ||
197 | if (!edev->pe) { | ||
198 | #ifdef DEBUG | ||
199 | pr_info("PCI: skip building address cache for=%s - %s\n", | ||
200 | pci_name(dev), dn->full_name); | ||
201 | #endif | ||
202 | return; | ||
203 | } | ||
204 | |||
205 | /* Walk resources on this device, poke them into the tree */ | ||
206 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | ||
207 | unsigned long start = pci_resource_start(dev,i); | ||
208 | unsigned long end = pci_resource_end(dev,i); | ||
209 | unsigned int flags = pci_resource_flags(dev,i); | ||
210 | |||
211 | /* We are interested only bus addresses, not dma or other stuff */ | ||
212 | if (0 == (flags & (IORESOURCE_IO | IORESOURCE_MEM))) | ||
213 | continue; | ||
214 | if (start == 0 || ~start == 0 || end == 0 || ~end == 0) | ||
215 | continue; | ||
216 | eeh_addr_cache_insert(dev, start, end, flags); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * eeh_addr_cache_insert_dev - Add a device to the address cache | ||
222 | * @dev: PCI device whose I/O addresses we are interested in. | ||
223 | * | ||
224 | * In order to support the fast lookup of devices based on addresses, | ||
225 | * we maintain a cache of devices that can be quickly searched. | ||
226 | * This routine adds a device to that cache. | ||
227 | */ | ||
228 | void eeh_addr_cache_insert_dev(struct pci_dev *dev) | ||
229 | { | ||
230 | unsigned long flags; | ||
231 | |||
232 | /* Ignore PCI bridges */ | ||
233 | if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) | ||
234 | return; | ||
235 | |||
236 | spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); | ||
237 | __eeh_addr_cache_insert_dev(dev); | ||
238 | spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); | ||
239 | } | ||
240 | |||
241 | static inline void __eeh_addr_cache_rmv_dev(struct pci_dev *dev) | ||
242 | { | ||
243 | struct rb_node *n; | ||
244 | |||
245 | restart: | ||
246 | n = rb_first(&pci_io_addr_cache_root.rb_root); | ||
247 | while (n) { | ||
248 | struct pci_io_addr_range *piar; | ||
249 | piar = rb_entry(n, struct pci_io_addr_range, rb_node); | ||
250 | |||
251 | if (piar->pcidev == dev) { | ||
252 | rb_erase(n, &pci_io_addr_cache_root.rb_root); | ||
253 | pci_dev_put(piar->pcidev); | ||
254 | kfree(piar); | ||
255 | goto restart; | ||
256 | } | ||
257 | n = rb_next(n); | ||
258 | } | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * eeh_addr_cache_rmv_dev - remove pci device from addr cache | ||
263 | * @dev: device to remove | ||
264 | * | ||
265 | * Remove a device from the addr-cache tree. | ||
266 | * This is potentially expensive, since it will walk | ||
267 | * the tree multiple times (once per resource). | ||
268 | * But so what; device removal doesn't need to be that fast. | ||
269 | */ | ||
270 | void eeh_addr_cache_rmv_dev(struct pci_dev *dev) | ||
271 | { | ||
272 | unsigned long flags; | ||
273 | |||
274 | spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); | ||
275 | __eeh_addr_cache_rmv_dev(dev); | ||
276 | spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * eeh_addr_cache_build - Build a cache of I/O addresses | ||
281 | * | ||
282 | * Build a cache of pci i/o addresses. This cache will be used to | ||
283 | * find the pci device that corresponds to a given address. | ||
284 | * This routine scans all pci busses to build the cache. | ||
285 | * Must be run late in boot process, after the pci controllers | ||
286 | * have been scanned for devices (after all device resources are known). | ||
287 | */ | ||
288 | void __init eeh_addr_cache_build(void) | ||
289 | { | ||
290 | struct device_node *dn; | ||
291 | struct eeh_dev *edev; | ||
292 | struct pci_dev *dev = NULL; | ||
293 | |||
294 | spin_lock_init(&pci_io_addr_cache_root.piar_lock); | ||
295 | |||
296 | for_each_pci_dev(dev) { | ||
297 | eeh_addr_cache_insert_dev(dev); | ||
298 | |||
299 | dn = pci_device_to_OF_node(dev); | ||
300 | if (!dn) | ||
301 | continue; | ||
302 | |||
303 | edev = of_node_to_eeh_dev(dn); | ||
304 | if (!edev) | ||
305 | continue; | ||
306 | |||
307 | pci_dev_get(dev); /* matching put is in eeh_remove_device() */ | ||
308 | dev->dev.archdata.edev = edev; | ||
309 | edev->pdev = dev; | ||
310 | |||
311 | eeh_sysfs_add_device(dev); | ||
312 | } | ||
313 | |||
314 | #ifdef DEBUG | ||
315 | /* Verify tree built up above, echo back the list of addrs. */ | ||
316 | eeh_addr_cache_print(&pci_io_addr_cache_root); | ||
317 | #endif | ||
318 | } | ||
319 | |||
diff --git a/arch/powerpc/platforms/pseries/eeh_dev.c b/arch/powerpc/platforms/pseries/eeh_dev.c deleted file mode 100644 index 1efa28f5fc54..000000000000 --- a/arch/powerpc/platforms/pseries/eeh_dev.c +++ /dev/null | |||
@@ -1,112 +0,0 @@ | |||
1 | /* | ||
2 | * The file intends to implement dynamic creation of EEH device, which will | ||
3 | * be bound with OF node and PCI device simutaneously. The EEH devices would | ||
4 | * be foundamental information for EEH core components to work proerly. Besides, | ||
5 | * We have to support multiple situations where dynamic creation of EEH device | ||
6 | * is required: | ||
7 | * | ||
8 | * 1) Before PCI emunation starts, we need create EEH devices according to the | ||
9 | * PCI sensitive OF nodes. | ||
10 | * 2) When PCI emunation is done, we need do the binding between PCI device and | ||
11 | * the associated EEH device. | ||
12 | * 3) DR (Dynamic Reconfiguration) would create PCI sensitive OF node. EEH device | ||
13 | * will be created while PCI sensitive OF node is detected from DR. | ||
14 | * 4) PCI hotplug needs redoing the binding between PCI device and EEH device. If | ||
15 | * PHB is newly inserted, we also need create EEH devices accordingly. | ||
16 | * | ||
17 | * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012. | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or modify | ||
20 | * it under the terms of the GNU General Public License as published by | ||
21 | * the Free Software Foundation; either version 2 of the License, or | ||
22 | * (at your option) any later version. | ||
23 | * | ||
24 | * This program is distributed in the hope that it will be useful, | ||
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
27 | * GNU General Public License for more details. | ||
28 | * | ||
29 | * You should have received a copy of the GNU General Public License | ||
30 | * along with this program; if not, write to the Free Software | ||
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
32 | */ | ||
33 | |||
34 | #include <linux/export.h> | ||
35 | #include <linux/gfp.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/pci.h> | ||
39 | #include <linux/string.h> | ||
40 | |||
41 | #include <asm/pci-bridge.h> | ||
42 | #include <asm/ppc-pci.h> | ||
43 | |||
44 | /** | ||
45 | * eeh_dev_init - Create EEH device according to OF node | ||
46 | * @dn: device node | ||
47 | * @data: PHB | ||
48 | * | ||
49 | * It will create EEH device according to the given OF node. The function | ||
50 | * might be called by PCI emunation, DR, PHB hotplug. | ||
51 | */ | ||
52 | void *eeh_dev_init(struct device_node *dn, void *data) | ||
53 | { | ||
54 | struct pci_controller *phb = data; | ||
55 | struct eeh_dev *edev; | ||
56 | |||
57 | /* Allocate EEH device */ | ||
58 | edev = kzalloc(sizeof(*edev), GFP_KERNEL); | ||
59 | if (!edev) { | ||
60 | pr_warning("%s: out of memory\n", __func__); | ||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | /* Associate EEH device with OF node */ | ||
65 | PCI_DN(dn)->edev = edev; | ||
66 | edev->dn = dn; | ||
67 | edev->phb = phb; | ||
68 | INIT_LIST_HEAD(&edev->list); | ||
69 | |||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * eeh_dev_phb_init_dynamic - Create EEH devices for devices included in PHB | ||
75 | * @phb: PHB | ||
76 | * | ||
77 | * Scan the PHB OF node and its child association, then create the | ||
78 | * EEH devices accordingly | ||
79 | */ | ||
80 | void eeh_dev_phb_init_dynamic(struct pci_controller *phb) | ||
81 | { | ||
82 | struct device_node *dn = phb->dn; | ||
83 | |||
84 | /* EEH PE for PHB */ | ||
85 | eeh_phb_pe_create(phb); | ||
86 | |||
87 | /* EEH device for PHB */ | ||
88 | eeh_dev_init(dn, phb); | ||
89 | |||
90 | /* EEH devices for children OF nodes */ | ||
91 | traverse_pci_devices(dn, eeh_dev_init, phb); | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * eeh_dev_phb_init - Create EEH devices for devices included in existing PHBs | ||
96 | * | ||
97 | * Scan all the existing PHBs and create EEH devices for their OF | ||
98 | * nodes and their children OF nodes | ||
99 | */ | ||
100 | static int __init eeh_dev_phb_init(void) | ||
101 | { | ||
102 | struct pci_controller *phb, *tmp; | ||
103 | |||
104 | list_for_each_entry_safe(phb, tmp, &hose_list, list_node) | ||
105 | eeh_dev_phb_init_dynamic(phb); | ||
106 | |||
107 | pr_info("EEH: devices created\n"); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | core_initcall(eeh_dev_phb_init); | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c deleted file mode 100644 index 0acc5a2bdfc7..000000000000 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ /dev/null | |||
@@ -1,552 +0,0 @@ | |||
1 | /* | ||
2 | * PCI Error Recovery Driver for RPA-compliant PPC64 platform. | ||
3 | * Copyright IBM Corp. 2004 2005 | ||
4 | * Copyright Linas Vepstas <linas@linas.org> 2004, 2005 | ||
5 | * | ||
6 | * All rights reserved. | ||
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 (at | ||
11 | * your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
16 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | * Send comments and feedback to Linas Vepstas <linas@austin.ibm.com> | ||
24 | */ | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/irq.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <asm/eeh.h> | ||
31 | #include <asm/eeh_event.h> | ||
32 | #include <asm/ppc-pci.h> | ||
33 | #include <asm/pci-bridge.h> | ||
34 | #include <asm/prom.h> | ||
35 | #include <asm/rtas.h> | ||
36 | |||
37 | /** | ||
38 | * eeh_pcid_name - Retrieve name of PCI device driver | ||
39 | * @pdev: PCI device | ||
40 | * | ||
41 | * This routine is used to retrieve the name of PCI device driver | ||
42 | * if that's valid. | ||
43 | */ | ||
44 | static inline const char *eeh_pcid_name(struct pci_dev *pdev) | ||
45 | { | ||
46 | if (pdev && pdev->dev.driver) | ||
47 | return pdev->dev.driver->name; | ||
48 | return ""; | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * eeh_pcid_get - Get the PCI device driver | ||
53 | * @pdev: PCI device | ||
54 | * | ||
55 | * The function is used to retrieve the PCI device driver for | ||
56 | * the indicated PCI device. Besides, we will increase the reference | ||
57 | * of the PCI device driver to prevent that being unloaded on | ||
58 | * the fly. Otherwise, kernel crash would be seen. | ||
59 | */ | ||
60 | static inline struct pci_driver *eeh_pcid_get(struct pci_dev *pdev) | ||
61 | { | ||
62 | if (!pdev || !pdev->driver) | ||
63 | return NULL; | ||
64 | |||
65 | if (!try_module_get(pdev->driver->driver.owner)) | ||
66 | return NULL; | ||
67 | |||
68 | return pdev->driver; | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * eeh_pcid_put - Dereference on the PCI device driver | ||
73 | * @pdev: PCI device | ||
74 | * | ||
75 | * The function is called to do dereference on the PCI device | ||
76 | * driver of the indicated PCI device. | ||
77 | */ | ||
78 | static inline void eeh_pcid_put(struct pci_dev *pdev) | ||
79 | { | ||
80 | if (!pdev || !pdev->driver) | ||
81 | return; | ||
82 | |||
83 | module_put(pdev->driver->driver.owner); | ||
84 | } | ||
85 | |||
86 | #if 0 | ||
87 | static void print_device_node_tree(struct pci_dn *pdn, int dent) | ||
88 | { | ||
89 | int i; | ||
90 | struct device_node *pc; | ||
91 | |||
92 | if (!pdn) | ||
93 | return; | ||
94 | for (i = 0; i < dent; i++) | ||
95 | printk(" "); | ||
96 | printk("dn=%s mode=%x \tcfg_addr=%x pe_addr=%x \tfull=%s\n", | ||
97 | pdn->node->name, pdn->eeh_mode, pdn->eeh_config_addr, | ||
98 | pdn->eeh_pe_config_addr, pdn->node->full_name); | ||
99 | dent += 3; | ||
100 | pc = pdn->node->child; | ||
101 | while (pc) { | ||
102 | print_device_node_tree(PCI_DN(pc), dent); | ||
103 | pc = pc->sibling; | ||
104 | } | ||
105 | } | ||
106 | #endif | ||
107 | |||
108 | /** | ||
109 | * eeh_disable_irq - Disable interrupt for the recovering device | ||
110 | * @dev: PCI device | ||
111 | * | ||
112 | * This routine must be called when reporting temporary or permanent | ||
113 | * error to the particular PCI device to disable interrupt of that | ||
114 | * device. If the device has enabled MSI or MSI-X interrupt, we needn't | ||
115 | * do real work because EEH should freeze DMA transfers for those PCI | ||
116 | * devices encountering EEH errors, which includes MSI or MSI-X. | ||
117 | */ | ||
118 | static void eeh_disable_irq(struct pci_dev *dev) | ||
119 | { | ||
120 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); | ||
121 | |||
122 | /* Don't disable MSI and MSI-X interrupts. They are | ||
123 | * effectively disabled by the DMA Stopped state | ||
124 | * when an EEH error occurs. | ||
125 | */ | ||
126 | if (dev->msi_enabled || dev->msix_enabled) | ||
127 | return; | ||
128 | |||
129 | if (!irq_has_action(dev->irq)) | ||
130 | return; | ||
131 | |||
132 | edev->mode |= EEH_DEV_IRQ_DISABLED; | ||
133 | disable_irq_nosync(dev->irq); | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * eeh_enable_irq - Enable interrupt for the recovering device | ||
138 | * @dev: PCI device | ||
139 | * | ||
140 | * This routine must be called to enable interrupt while failed | ||
141 | * device could be resumed. | ||
142 | */ | ||
143 | static void eeh_enable_irq(struct pci_dev *dev) | ||
144 | { | ||
145 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); | ||
146 | |||
147 | if ((edev->mode) & EEH_DEV_IRQ_DISABLED) { | ||
148 | edev->mode &= ~EEH_DEV_IRQ_DISABLED; | ||
149 | enable_irq(dev->irq); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * eeh_report_error - Report pci error to each device driver | ||
155 | * @data: eeh device | ||
156 | * @userdata: return value | ||
157 | * | ||
158 | * Report an EEH error to each device driver, collect up and | ||
159 | * merge the device driver responses. Cumulative response | ||
160 | * passed back in "userdata". | ||
161 | */ | ||
162 | static void *eeh_report_error(void *data, void *userdata) | ||
163 | { | ||
164 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
165 | struct pci_dev *dev = eeh_dev_to_pci_dev(edev); | ||
166 | enum pci_ers_result rc, *res = userdata; | ||
167 | struct pci_driver *driver; | ||
168 | |||
169 | /* We might not have the associated PCI device, | ||
170 | * then we should continue for next one. | ||
171 | */ | ||
172 | if (!dev) return NULL; | ||
173 | dev->error_state = pci_channel_io_frozen; | ||
174 | |||
175 | driver = eeh_pcid_get(dev); | ||
176 | if (!driver) return NULL; | ||
177 | |||
178 | eeh_disable_irq(dev); | ||
179 | |||
180 | if (!driver->err_handler || | ||
181 | !driver->err_handler->error_detected) { | ||
182 | eeh_pcid_put(dev); | ||
183 | return NULL; | ||
184 | } | ||
185 | |||
186 | rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen); | ||
187 | |||
188 | /* A driver that needs a reset trumps all others */ | ||
189 | if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; | ||
190 | if (*res == PCI_ERS_RESULT_NONE) *res = rc; | ||
191 | |||
192 | eeh_pcid_put(dev); | ||
193 | return NULL; | ||
194 | } | ||
195 | |||
196 | /** | ||
197 | * eeh_report_mmio_enabled - Tell drivers that MMIO has been enabled | ||
198 | * @data: eeh device | ||
199 | * @userdata: return value | ||
200 | * | ||
201 | * Tells each device driver that IO ports, MMIO and config space I/O | ||
202 | * are now enabled. Collects up and merges the device driver responses. | ||
203 | * Cumulative response passed back in "userdata". | ||
204 | */ | ||
205 | static void *eeh_report_mmio_enabled(void *data, void *userdata) | ||
206 | { | ||
207 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
208 | struct pci_dev *dev = eeh_dev_to_pci_dev(edev); | ||
209 | enum pci_ers_result rc, *res = userdata; | ||
210 | struct pci_driver *driver; | ||
211 | |||
212 | driver = eeh_pcid_get(dev); | ||
213 | if (!driver) return NULL; | ||
214 | |||
215 | if (!driver->err_handler || | ||
216 | !driver->err_handler->mmio_enabled) { | ||
217 | eeh_pcid_put(dev); | ||
218 | return NULL; | ||
219 | } | ||
220 | |||
221 | rc = driver->err_handler->mmio_enabled(dev); | ||
222 | |||
223 | /* A driver that needs a reset trumps all others */ | ||
224 | if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; | ||
225 | if (*res == PCI_ERS_RESULT_NONE) *res = rc; | ||
226 | |||
227 | eeh_pcid_put(dev); | ||
228 | return NULL; | ||
229 | } | ||
230 | |||
231 | /** | ||
232 | * eeh_report_reset - Tell device that slot has been reset | ||
233 | * @data: eeh device | ||
234 | * @userdata: return value | ||
235 | * | ||
236 | * This routine must be called while EEH tries to reset particular | ||
237 | * PCI device so that the associated PCI device driver could take | ||
238 | * some actions, usually to save data the driver needs so that the | ||
239 | * driver can work again while the device is recovered. | ||
240 | */ | ||
241 | static void *eeh_report_reset(void *data, void *userdata) | ||
242 | { | ||
243 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
244 | struct pci_dev *dev = eeh_dev_to_pci_dev(edev); | ||
245 | enum pci_ers_result rc, *res = userdata; | ||
246 | struct pci_driver *driver; | ||
247 | |||
248 | if (!dev) return NULL; | ||
249 | dev->error_state = pci_channel_io_normal; | ||
250 | |||
251 | driver = eeh_pcid_get(dev); | ||
252 | if (!driver) return NULL; | ||
253 | |||
254 | eeh_enable_irq(dev); | ||
255 | |||
256 | if (!driver->err_handler || | ||
257 | !driver->err_handler->slot_reset) { | ||
258 | eeh_pcid_put(dev); | ||
259 | return NULL; | ||
260 | } | ||
261 | |||
262 | rc = driver->err_handler->slot_reset(dev); | ||
263 | if ((*res == PCI_ERS_RESULT_NONE) || | ||
264 | (*res == PCI_ERS_RESULT_RECOVERED)) *res = rc; | ||
265 | if (*res == PCI_ERS_RESULT_DISCONNECT && | ||
266 | rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; | ||
267 | |||
268 | eeh_pcid_put(dev); | ||
269 | return NULL; | ||
270 | } | ||
271 | |||
272 | /** | ||
273 | * eeh_report_resume - Tell device to resume normal operations | ||
274 | * @data: eeh device | ||
275 | * @userdata: return value | ||
276 | * | ||
277 | * This routine must be called to notify the device driver that it | ||
278 | * could resume so that the device driver can do some initialization | ||
279 | * to make the recovered device work again. | ||
280 | */ | ||
281 | static void *eeh_report_resume(void *data, void *userdata) | ||
282 | { | ||
283 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
284 | struct pci_dev *dev = eeh_dev_to_pci_dev(edev); | ||
285 | struct pci_driver *driver; | ||
286 | |||
287 | if (!dev) return NULL; | ||
288 | dev->error_state = pci_channel_io_normal; | ||
289 | |||
290 | driver = eeh_pcid_get(dev); | ||
291 | if (!driver) return NULL; | ||
292 | |||
293 | eeh_enable_irq(dev); | ||
294 | |||
295 | if (!driver->err_handler || | ||
296 | !driver->err_handler->resume) { | ||
297 | eeh_pcid_put(dev); | ||
298 | return NULL; | ||
299 | } | ||
300 | |||
301 | driver->err_handler->resume(dev); | ||
302 | |||
303 | eeh_pcid_put(dev); | ||
304 | return NULL; | ||
305 | } | ||
306 | |||
307 | /** | ||
308 | * eeh_report_failure - Tell device driver that device is dead. | ||
309 | * @data: eeh device | ||
310 | * @userdata: return value | ||
311 | * | ||
312 | * This informs the device driver that the device is permanently | ||
313 | * dead, and that no further recovery attempts will be made on it. | ||
314 | */ | ||
315 | static void *eeh_report_failure(void *data, void *userdata) | ||
316 | { | ||
317 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
318 | struct pci_dev *dev = eeh_dev_to_pci_dev(edev); | ||
319 | struct pci_driver *driver; | ||
320 | |||
321 | if (!dev) return NULL; | ||
322 | dev->error_state = pci_channel_io_perm_failure; | ||
323 | |||
324 | driver = eeh_pcid_get(dev); | ||
325 | if (!driver) return NULL; | ||
326 | |||
327 | eeh_disable_irq(dev); | ||
328 | |||
329 | if (!driver->err_handler || | ||
330 | !driver->err_handler->error_detected) { | ||
331 | eeh_pcid_put(dev); | ||
332 | return NULL; | ||
333 | } | ||
334 | |||
335 | driver->err_handler->error_detected(dev, pci_channel_io_perm_failure); | ||
336 | |||
337 | eeh_pcid_put(dev); | ||
338 | return NULL; | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * eeh_reset_device - Perform actual reset of a pci slot | ||
343 | * @pe: EEH PE | ||
344 | * @bus: PCI bus corresponding to the isolcated slot | ||
345 | * | ||
346 | * This routine must be called to do reset on the indicated PE. | ||
347 | * During the reset, udev might be invoked because those affected | ||
348 | * PCI devices will be removed and then added. | ||
349 | */ | ||
350 | static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) | ||
351 | { | ||
352 | int cnt, rc; | ||
353 | |||
354 | /* pcibios will clear the counter; save the value */ | ||
355 | cnt = pe->freeze_count; | ||
356 | |||
357 | /* | ||
358 | * We don't remove the corresponding PE instances because | ||
359 | * we need the information afterwords. The attached EEH | ||
360 | * devices are expected to be attached soon when calling | ||
361 | * into pcibios_add_pci_devices(). | ||
362 | */ | ||
363 | if (bus) | ||
364 | __pcibios_remove_pci_devices(bus, 0); | ||
365 | |||
366 | /* Reset the pci controller. (Asserts RST#; resets config space). | ||
367 | * Reconfigure bridges and devices. Don't try to bring the system | ||
368 | * up if the reset failed for some reason. | ||
369 | */ | ||
370 | rc = eeh_reset_pe(pe); | ||
371 | if (rc) | ||
372 | return rc; | ||
373 | |||
374 | /* Restore PE */ | ||
375 | eeh_ops->configure_bridge(pe); | ||
376 | eeh_pe_restore_bars(pe); | ||
377 | |||
378 | /* Give the system 5 seconds to finish running the user-space | ||
379 | * hotplug shutdown scripts, e.g. ifdown for ethernet. Yes, | ||
380 | * this is a hack, but if we don't do this, and try to bring | ||
381 | * the device up before the scripts have taken it down, | ||
382 | * potentially weird things happen. | ||
383 | */ | ||
384 | if (bus) { | ||
385 | ssleep(5); | ||
386 | pcibios_add_pci_devices(bus); | ||
387 | } | ||
388 | pe->freeze_count = cnt; | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | /* The longest amount of time to wait for a pci device | ||
394 | * to come back on line, in seconds. | ||
395 | */ | ||
396 | #define MAX_WAIT_FOR_RECOVERY 150 | ||
397 | |||
398 | /** | ||
399 | * eeh_handle_event - Reset a PCI device after hard lockup. | ||
400 | * @pe: EEH PE | ||
401 | * | ||
402 | * While PHB detects address or data parity errors on particular PCI | ||
403 | * slot, the associated PE will be frozen. Besides, DMA's occurring | ||
404 | * to wild addresses (which usually happen due to bugs in device | ||
405 | * drivers or in PCI adapter firmware) can cause EEH error. #SERR, | ||
406 | * #PERR or other misc PCI-related errors also can trigger EEH errors. | ||
407 | * | ||
408 | * Recovery process consists of unplugging the device driver (which | ||
409 | * generated hotplug events to userspace), then issuing a PCI #RST to | ||
410 | * the device, then reconfiguring the PCI config space for all bridges | ||
411 | * & devices under this slot, and then finally restarting the device | ||
412 | * drivers (which cause a second set of hotplug events to go out to | ||
413 | * userspace). | ||
414 | */ | ||
415 | void eeh_handle_event(struct eeh_pe *pe) | ||
416 | { | ||
417 | struct pci_bus *frozen_bus; | ||
418 | int rc = 0; | ||
419 | enum pci_ers_result result = PCI_ERS_RESULT_NONE; | ||
420 | |||
421 | frozen_bus = eeh_pe_bus_get(pe); | ||
422 | if (!frozen_bus) { | ||
423 | pr_err("%s: Cannot find PCI bus for PHB#%d-PE#%x\n", | ||
424 | __func__, pe->phb->global_number, pe->addr); | ||
425 | return; | ||
426 | } | ||
427 | |||
428 | pe->freeze_count++; | ||
429 | if (pe->freeze_count > EEH_MAX_ALLOWED_FREEZES) | ||
430 | goto excess_failures; | ||
431 | pr_warning("EEH: This PCI device has failed %d times in the last hour\n", | ||
432 | pe->freeze_count); | ||
433 | |||
434 | /* Walk the various device drivers attached to this slot through | ||
435 | * a reset sequence, giving each an opportunity to do what it needs | ||
436 | * to accomplish the reset. Each child gets a report of the | ||
437 | * status ... if any child can't handle the reset, then the entire | ||
438 | * slot is dlpar removed and added. | ||
439 | */ | ||
440 | eeh_pe_dev_traverse(pe, eeh_report_error, &result); | ||
441 | |||
442 | /* Get the current PCI slot state. This can take a long time, | ||
443 | * sometimes over 3 seconds for certain systems. | ||
444 | */ | ||
445 | rc = eeh_ops->wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000); | ||
446 | if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) { | ||
447 | printk(KERN_WARNING "EEH: Permanent failure\n"); | ||
448 | goto hard_fail; | ||
449 | } | ||
450 | |||
451 | /* Since rtas may enable MMIO when posting the error log, | ||
452 | * don't post the error log until after all dev drivers | ||
453 | * have been informed. | ||
454 | */ | ||
455 | eeh_slot_error_detail(pe, EEH_LOG_TEMP); | ||
456 | |||
457 | /* If all device drivers were EEH-unaware, then shut | ||
458 | * down all of the device drivers, and hope they | ||
459 | * go down willingly, without panicing the system. | ||
460 | */ | ||
461 | if (result == PCI_ERS_RESULT_NONE) { | ||
462 | rc = eeh_reset_device(pe, frozen_bus); | ||
463 | if (rc) { | ||
464 | printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc); | ||
465 | goto hard_fail; | ||
466 | } | ||
467 | } | ||
468 | |||
469 | /* If all devices reported they can proceed, then re-enable MMIO */ | ||
470 | if (result == PCI_ERS_RESULT_CAN_RECOVER) { | ||
471 | rc = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); | ||
472 | |||
473 | if (rc < 0) | ||
474 | goto hard_fail; | ||
475 | if (rc) { | ||
476 | result = PCI_ERS_RESULT_NEED_RESET; | ||
477 | } else { | ||
478 | result = PCI_ERS_RESULT_NONE; | ||
479 | eeh_pe_dev_traverse(pe, eeh_report_mmio_enabled, &result); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | /* If all devices reported they can proceed, then re-enable DMA */ | ||
484 | if (result == PCI_ERS_RESULT_CAN_RECOVER) { | ||
485 | rc = eeh_pci_enable(pe, EEH_OPT_THAW_DMA); | ||
486 | |||
487 | if (rc < 0) | ||
488 | goto hard_fail; | ||
489 | if (rc) | ||
490 | result = PCI_ERS_RESULT_NEED_RESET; | ||
491 | else | ||
492 | result = PCI_ERS_RESULT_RECOVERED; | ||
493 | } | ||
494 | |||
495 | /* If any device has a hard failure, then shut off everything. */ | ||
496 | if (result == PCI_ERS_RESULT_DISCONNECT) { | ||
497 | printk(KERN_WARNING "EEH: Device driver gave up\n"); | ||
498 | goto hard_fail; | ||
499 | } | ||
500 | |||
501 | /* If any device called out for a reset, then reset the slot */ | ||
502 | if (result == PCI_ERS_RESULT_NEED_RESET) { | ||
503 | rc = eeh_reset_device(pe, NULL); | ||
504 | if (rc) { | ||
505 | printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc); | ||
506 | goto hard_fail; | ||
507 | } | ||
508 | result = PCI_ERS_RESULT_NONE; | ||
509 | eeh_pe_dev_traverse(pe, eeh_report_reset, &result); | ||
510 | } | ||
511 | |||
512 | /* All devices should claim they have recovered by now. */ | ||
513 | if ((result != PCI_ERS_RESULT_RECOVERED) && | ||
514 | (result != PCI_ERS_RESULT_NONE)) { | ||
515 | printk(KERN_WARNING "EEH: Not recovered\n"); | ||
516 | goto hard_fail; | ||
517 | } | ||
518 | |||
519 | /* Tell all device drivers that they can resume operations */ | ||
520 | eeh_pe_dev_traverse(pe, eeh_report_resume, NULL); | ||
521 | |||
522 | return; | ||
523 | |||
524 | excess_failures: | ||
525 | /* | ||
526 | * About 90% of all real-life EEH failures in the field | ||
527 | * are due to poorly seated PCI cards. Only 10% or so are | ||
528 | * due to actual, failed cards. | ||
529 | */ | ||
530 | pr_err("EEH: PHB#%d-PE#%x has failed %d times in the\n" | ||
531 | "last hour and has been permanently disabled.\n" | ||
532 | "Please try reseating or replacing it.\n", | ||
533 | pe->phb->global_number, pe->addr, | ||
534 | pe->freeze_count); | ||
535 | goto perm_error; | ||
536 | |||
537 | hard_fail: | ||
538 | pr_err("EEH: Unable to recover from failure from PHB#%d-PE#%x.\n" | ||
539 | "Please try reseating or replacing it\n", | ||
540 | pe->phb->global_number, pe->addr); | ||
541 | |||
542 | perm_error: | ||
543 | eeh_slot_error_detail(pe, EEH_LOG_PERM); | ||
544 | |||
545 | /* Notify all devices that they're about to go down. */ | ||
546 | eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); | ||
547 | |||
548 | /* Shut down the device drivers for good. */ | ||
549 | if (frozen_bus) | ||
550 | pcibios_remove_pci_devices(frozen_bus); | ||
551 | } | ||
552 | |||
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c deleted file mode 100644 index 185bedd926df..000000000000 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ /dev/null | |||
@@ -1,142 +0,0 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
15 | * | ||
16 | * Copyright (c) 2005 Linas Vepstas <linas@linas.org> | ||
17 | */ | ||
18 | |||
19 | #include <linux/delay.h> | ||
20 | #include <linux/list.h> | ||
21 | #include <linux/mutex.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/workqueue.h> | ||
26 | #include <linux/kthread.h> | ||
27 | #include <asm/eeh_event.h> | ||
28 | #include <asm/ppc-pci.h> | ||
29 | |||
30 | /** Overview: | ||
31 | * EEH error states may be detected within exception handlers; | ||
32 | * however, the recovery processing needs to occur asynchronously | ||
33 | * in a normal kernel context and not an interrupt context. | ||
34 | * This pair of routines creates an event and queues it onto a | ||
35 | * work-queue, where a worker thread can drive recovery. | ||
36 | */ | ||
37 | |||
38 | /* EEH event workqueue setup. */ | ||
39 | static DEFINE_SPINLOCK(eeh_eventlist_lock); | ||
40 | LIST_HEAD(eeh_eventlist); | ||
41 | static void eeh_thread_launcher(struct work_struct *); | ||
42 | DECLARE_WORK(eeh_event_wq, eeh_thread_launcher); | ||
43 | |||
44 | /* Serialize reset sequences for a given pci device */ | ||
45 | DEFINE_MUTEX(eeh_event_mutex); | ||
46 | |||
47 | /** | ||
48 | * eeh_event_handler - Dispatch EEH events. | ||
49 | * @dummy - unused | ||
50 | * | ||
51 | * The detection of a frozen slot can occur inside an interrupt, | ||
52 | * where it can be hard to do anything about it. The goal of this | ||
53 | * routine is to pull these detection events out of the context | ||
54 | * of the interrupt handler, and re-dispatch them for processing | ||
55 | * at a later time in a normal context. | ||
56 | */ | ||
57 | static int eeh_event_handler(void * dummy) | ||
58 | { | ||
59 | unsigned long flags; | ||
60 | struct eeh_event *event; | ||
61 | struct eeh_pe *pe; | ||
62 | |||
63 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | ||
64 | event = NULL; | ||
65 | |||
66 | /* Unqueue the event, get ready to process. */ | ||
67 | if (!list_empty(&eeh_eventlist)) { | ||
68 | event = list_entry(eeh_eventlist.next, struct eeh_event, list); | ||
69 | list_del(&event->list); | ||
70 | } | ||
71 | spin_unlock_irqrestore(&eeh_eventlist_lock, flags); | ||
72 | |||
73 | if (event == NULL) | ||
74 | return 0; | ||
75 | |||
76 | /* Serialize processing of EEH events */ | ||
77 | mutex_lock(&eeh_event_mutex); | ||
78 | pe = event->pe; | ||
79 | eeh_pe_state_mark(pe, EEH_PE_RECOVERING); | ||
80 | pr_info("EEH: Detected PCI bus error on PHB#%d-PE#%x\n", | ||
81 | pe->phb->global_number, pe->addr); | ||
82 | |||
83 | set_current_state(TASK_INTERRUPTIBLE); /* Don't add to load average */ | ||
84 | eeh_handle_event(pe); | ||
85 | eeh_pe_state_clear(pe, EEH_PE_RECOVERING); | ||
86 | |||
87 | kfree(event); | ||
88 | mutex_unlock(&eeh_event_mutex); | ||
89 | |||
90 | /* If there are no new errors after an hour, clear the counter. */ | ||
91 | if (pe && pe->freeze_count > 0) { | ||
92 | msleep_interruptible(3600*1000); | ||
93 | if (pe->freeze_count > 0) | ||
94 | pe->freeze_count--; | ||
95 | |||
96 | } | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * eeh_thread_launcher - Start kernel thread to handle EEH events | ||
103 | * @dummy - unused | ||
104 | * | ||
105 | * This routine is called to start the kernel thread for processing | ||
106 | * EEH event. | ||
107 | */ | ||
108 | static void eeh_thread_launcher(struct work_struct *dummy) | ||
109 | { | ||
110 | if (IS_ERR(kthread_run(eeh_event_handler, NULL, "eehd"))) | ||
111 | printk(KERN_ERR "Failed to start EEH daemon\n"); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * eeh_send_failure_event - Generate a PCI error event | ||
116 | * @pe: EEH PE | ||
117 | * | ||
118 | * This routine can be called within an interrupt context; | ||
119 | * the actual event will be delivered in a normal context | ||
120 | * (from a workqueue). | ||
121 | */ | ||
122 | int eeh_send_failure_event(struct eeh_pe *pe) | ||
123 | { | ||
124 | unsigned long flags; | ||
125 | struct eeh_event *event; | ||
126 | |||
127 | event = kzalloc(sizeof(*event), GFP_ATOMIC); | ||
128 | if (!event) { | ||
129 | pr_err("EEH: out of memory, event not handled\n"); | ||
130 | return -ENOMEM; | ||
131 | } | ||
132 | event->pe = pe; | ||
133 | |||
134 | /* We may or may not be called in an interrupt context */ | ||
135 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | ||
136 | list_add(&event->list, &eeh_eventlist); | ||
137 | spin_unlock_irqrestore(&eeh_eventlist_lock, flags); | ||
138 | |||
139 | schedule_work(&eeh_event_wq); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c deleted file mode 100644 index 9d4a9e8562b2..000000000000 --- a/arch/powerpc/platforms/pseries/eeh_pe.c +++ /dev/null | |||
@@ -1,653 +0,0 @@ | |||
1 | /* | ||
2 | * The file intends to implement PE based on the information from | ||
3 | * platforms. Basically, there have 3 types of PEs: PHB/Bus/Device. | ||
4 | * All the PEs should be organized as hierarchy tree. The first level | ||
5 | * of the tree will be associated to existing PHBs since the particular | ||
6 | * PE is only meaningful in one PHB domain. | ||
7 | * | ||
8 | * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | #include <linux/export.h> | ||
26 | #include <linux/gfp.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/string.h> | ||
31 | |||
32 | #include <asm/pci-bridge.h> | ||
33 | #include <asm/ppc-pci.h> | ||
34 | |||
35 | static LIST_HEAD(eeh_phb_pe); | ||
36 | |||
37 | /** | ||
38 | * eeh_pe_alloc - Allocate PE | ||
39 | * @phb: PCI controller | ||
40 | * @type: PE type | ||
41 | * | ||
42 | * Allocate PE instance dynamically. | ||
43 | */ | ||
44 | static struct eeh_pe *eeh_pe_alloc(struct pci_controller *phb, int type) | ||
45 | { | ||
46 | struct eeh_pe *pe; | ||
47 | |||
48 | /* Allocate PHB PE */ | ||
49 | pe = kzalloc(sizeof(struct eeh_pe), GFP_KERNEL); | ||
50 | if (!pe) return NULL; | ||
51 | |||
52 | /* Initialize PHB PE */ | ||
53 | pe->type = type; | ||
54 | pe->phb = phb; | ||
55 | INIT_LIST_HEAD(&pe->child_list); | ||
56 | INIT_LIST_HEAD(&pe->child); | ||
57 | INIT_LIST_HEAD(&pe->edevs); | ||
58 | |||
59 | return pe; | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * eeh_phb_pe_create - Create PHB PE | ||
64 | * @phb: PCI controller | ||
65 | * | ||
66 | * The function should be called while the PHB is detected during | ||
67 | * system boot or PCI hotplug in order to create PHB PE. | ||
68 | */ | ||
69 | int eeh_phb_pe_create(struct pci_controller *phb) | ||
70 | { | ||
71 | struct eeh_pe *pe; | ||
72 | |||
73 | /* Allocate PHB PE */ | ||
74 | pe = eeh_pe_alloc(phb, EEH_PE_PHB); | ||
75 | if (!pe) { | ||
76 | pr_err("%s: out of memory!\n", __func__); | ||
77 | return -ENOMEM; | ||
78 | } | ||
79 | |||
80 | /* Put it into the list */ | ||
81 | eeh_lock(); | ||
82 | list_add_tail(&pe->child, &eeh_phb_pe); | ||
83 | eeh_unlock(); | ||
84 | |||
85 | pr_debug("EEH: Add PE for PHB#%d\n", phb->global_number); | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * eeh_phb_pe_get - Retrieve PHB PE based on the given PHB | ||
92 | * @phb: PCI controller | ||
93 | * | ||
94 | * The overall PEs form hierarchy tree. The first layer of the | ||
95 | * hierarchy tree is composed of PHB PEs. The function is used | ||
96 | * to retrieve the corresponding PHB PE according to the given PHB. | ||
97 | */ | ||
98 | static struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb) | ||
99 | { | ||
100 | struct eeh_pe *pe; | ||
101 | |||
102 | list_for_each_entry(pe, &eeh_phb_pe, child) { | ||
103 | /* | ||
104 | * Actually, we needn't check the type since | ||
105 | * the PE for PHB has been determined when that | ||
106 | * was created. | ||
107 | */ | ||
108 | if ((pe->type & EEH_PE_PHB) && pe->phb == phb) | ||
109 | return pe; | ||
110 | } | ||
111 | |||
112 | return NULL; | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * eeh_pe_next - Retrieve the next PE in the tree | ||
117 | * @pe: current PE | ||
118 | * @root: root PE | ||
119 | * | ||
120 | * The function is used to retrieve the next PE in the | ||
121 | * hierarchy PE tree. | ||
122 | */ | ||
123 | static struct eeh_pe *eeh_pe_next(struct eeh_pe *pe, | ||
124 | struct eeh_pe *root) | ||
125 | { | ||
126 | struct list_head *next = pe->child_list.next; | ||
127 | |||
128 | if (next == &pe->child_list) { | ||
129 | while (1) { | ||
130 | if (pe == root) | ||
131 | return NULL; | ||
132 | next = pe->child.next; | ||
133 | if (next != &pe->parent->child_list) | ||
134 | break; | ||
135 | pe = pe->parent; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | return list_entry(next, struct eeh_pe, child); | ||
140 | } | ||
141 | |||
142 | /** | ||
143 | * eeh_pe_traverse - Traverse PEs in the specified PHB | ||
144 | * @root: root PE | ||
145 | * @fn: callback | ||
146 | * @flag: extra parameter to callback | ||
147 | * | ||
148 | * The function is used to traverse the specified PE and its | ||
149 | * child PEs. The traversing is to be terminated once the | ||
150 | * callback returns something other than NULL, or no more PEs | ||
151 | * to be traversed. | ||
152 | */ | ||
153 | static void *eeh_pe_traverse(struct eeh_pe *root, | ||
154 | eeh_traverse_func fn, void *flag) | ||
155 | { | ||
156 | struct eeh_pe *pe; | ||
157 | void *ret; | ||
158 | |||
159 | for (pe = root; pe; pe = eeh_pe_next(pe, root)) { | ||
160 | ret = fn(pe, flag); | ||
161 | if (ret) return ret; | ||
162 | } | ||
163 | |||
164 | return NULL; | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * eeh_pe_dev_traverse - Traverse the devices from the PE | ||
169 | * @root: EEH PE | ||
170 | * @fn: function callback | ||
171 | * @flag: extra parameter to callback | ||
172 | * | ||
173 | * The function is used to traverse the devices of the specified | ||
174 | * PE and its child PEs. | ||
175 | */ | ||
176 | void *eeh_pe_dev_traverse(struct eeh_pe *root, | ||
177 | eeh_traverse_func fn, void *flag) | ||
178 | { | ||
179 | struct eeh_pe *pe; | ||
180 | struct eeh_dev *edev; | ||
181 | void *ret; | ||
182 | |||
183 | if (!root) { | ||
184 | pr_warning("%s: Invalid PE %p\n", __func__, root); | ||
185 | return NULL; | ||
186 | } | ||
187 | |||
188 | eeh_lock(); | ||
189 | |||
190 | /* Traverse root PE */ | ||
191 | for (pe = root; pe; pe = eeh_pe_next(pe, root)) { | ||
192 | eeh_pe_for_each_dev(pe, edev) { | ||
193 | ret = fn(edev, flag); | ||
194 | if (ret) { | ||
195 | eeh_unlock(); | ||
196 | return ret; | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | eeh_unlock(); | ||
202 | |||
203 | return NULL; | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * __eeh_pe_get - Check the PE address | ||
208 | * @data: EEH PE | ||
209 | * @flag: EEH device | ||
210 | * | ||
211 | * For one particular PE, it can be identified by PE address | ||
212 | * or tranditional BDF address. BDF address is composed of | ||
213 | * Bus/Device/Function number. The extra data referred by flag | ||
214 | * indicates which type of address should be used. | ||
215 | */ | ||
216 | static void *__eeh_pe_get(void *data, void *flag) | ||
217 | { | ||
218 | struct eeh_pe *pe = (struct eeh_pe *)data; | ||
219 | struct eeh_dev *edev = (struct eeh_dev *)flag; | ||
220 | |||
221 | /* Unexpected PHB PE */ | ||
222 | if (pe->type & EEH_PE_PHB) | ||
223 | return NULL; | ||
224 | |||
225 | /* We prefer PE address */ | ||
226 | if (edev->pe_config_addr && | ||
227 | (edev->pe_config_addr == pe->addr)) | ||
228 | return pe; | ||
229 | |||
230 | /* Try BDF address */ | ||
231 | if (edev->pe_config_addr && | ||
232 | (edev->config_addr == pe->config_addr)) | ||
233 | return pe; | ||
234 | |||
235 | return NULL; | ||
236 | } | ||
237 | |||
238 | /** | ||
239 | * eeh_pe_get - Search PE based on the given address | ||
240 | * @edev: EEH device | ||
241 | * | ||
242 | * Search the corresponding PE based on the specified address which | ||
243 | * is included in the eeh device. The function is used to check if | ||
244 | * the associated PE has been created against the PE address. It's | ||
245 | * notable that the PE address has 2 format: traditional PE address | ||
246 | * which is composed of PCI bus/device/function number, or unified | ||
247 | * PE address. | ||
248 | */ | ||
249 | static struct eeh_pe *eeh_pe_get(struct eeh_dev *edev) | ||
250 | { | ||
251 | struct eeh_pe *root = eeh_phb_pe_get(edev->phb); | ||
252 | struct eeh_pe *pe; | ||
253 | |||
254 | pe = eeh_pe_traverse(root, __eeh_pe_get, edev); | ||
255 | |||
256 | return pe; | ||
257 | } | ||
258 | |||
259 | /** | ||
260 | * eeh_pe_get_parent - Retrieve the parent PE | ||
261 | * @edev: EEH device | ||
262 | * | ||
263 | * The whole PEs existing in the system are organized as hierarchy | ||
264 | * tree. The function is used to retrieve the parent PE according | ||
265 | * to the parent EEH device. | ||
266 | */ | ||
267 | static struct eeh_pe *eeh_pe_get_parent(struct eeh_dev *edev) | ||
268 | { | ||
269 | struct device_node *dn; | ||
270 | struct eeh_dev *parent; | ||
271 | |||
272 | /* | ||
273 | * It might have the case for the indirect parent | ||
274 | * EEH device already having associated PE, but | ||
275 | * the direct parent EEH device doesn't have yet. | ||
276 | */ | ||
277 | dn = edev->dn->parent; | ||
278 | while (dn) { | ||
279 | /* We're poking out of PCI territory */ | ||
280 | if (!PCI_DN(dn)) return NULL; | ||
281 | |||
282 | parent = of_node_to_eeh_dev(dn); | ||
283 | /* We're poking out of PCI territory */ | ||
284 | if (!parent) return NULL; | ||
285 | |||
286 | if (parent->pe) | ||
287 | return parent->pe; | ||
288 | |||
289 | dn = dn->parent; | ||
290 | } | ||
291 | |||
292 | return NULL; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * eeh_add_to_parent_pe - Add EEH device to parent PE | ||
297 | * @edev: EEH device | ||
298 | * | ||
299 | * Add EEH device to the parent PE. If the parent PE already | ||
300 | * exists, the PE type will be changed to EEH_PE_BUS. Otherwise, | ||
301 | * we have to create new PE to hold the EEH device and the new | ||
302 | * PE will be linked to its parent PE as well. | ||
303 | */ | ||
304 | int eeh_add_to_parent_pe(struct eeh_dev *edev) | ||
305 | { | ||
306 | struct eeh_pe *pe, *parent; | ||
307 | |||
308 | eeh_lock(); | ||
309 | |||
310 | /* | ||
311 | * Search the PE has been existing or not according | ||
312 | * to the PE address. If that has been existing, the | ||
313 | * PE should be composed of PCI bus and its subordinate | ||
314 | * components. | ||
315 | */ | ||
316 | pe = eeh_pe_get(edev); | ||
317 | if (pe && !(pe->type & EEH_PE_INVALID)) { | ||
318 | if (!edev->pe_config_addr) { | ||
319 | eeh_unlock(); | ||
320 | pr_err("%s: PE with addr 0x%x already exists\n", | ||
321 | __func__, edev->config_addr); | ||
322 | return -EEXIST; | ||
323 | } | ||
324 | |||
325 | /* Mark the PE as type of PCI bus */ | ||
326 | pe->type = EEH_PE_BUS; | ||
327 | edev->pe = pe; | ||
328 | |||
329 | /* Put the edev to PE */ | ||
330 | list_add_tail(&edev->list, &pe->edevs); | ||
331 | eeh_unlock(); | ||
332 | pr_debug("EEH: Add %s to Bus PE#%x\n", | ||
333 | edev->dn->full_name, pe->addr); | ||
334 | |||
335 | return 0; | ||
336 | } else if (pe && (pe->type & EEH_PE_INVALID)) { | ||
337 | list_add_tail(&edev->list, &pe->edevs); | ||
338 | edev->pe = pe; | ||
339 | /* | ||
340 | * We're running to here because of PCI hotplug caused by | ||
341 | * EEH recovery. We need clear EEH_PE_INVALID until the top. | ||
342 | */ | ||
343 | parent = pe; | ||
344 | while (parent) { | ||
345 | if (!(parent->type & EEH_PE_INVALID)) | ||
346 | break; | ||
347 | parent->type &= ~EEH_PE_INVALID; | ||
348 | parent = parent->parent; | ||
349 | } | ||
350 | eeh_unlock(); | ||
351 | pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", | ||
352 | edev->dn->full_name, pe->addr, pe->parent->addr); | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /* Create a new EEH PE */ | ||
358 | pe = eeh_pe_alloc(edev->phb, EEH_PE_DEVICE); | ||
359 | if (!pe) { | ||
360 | eeh_unlock(); | ||
361 | pr_err("%s: out of memory!\n", __func__); | ||
362 | return -ENOMEM; | ||
363 | } | ||
364 | pe->addr = edev->pe_config_addr; | ||
365 | pe->config_addr = edev->config_addr; | ||
366 | |||
367 | /* | ||
368 | * Put the new EEH PE into hierarchy tree. If the parent | ||
369 | * can't be found, the newly created PE will be attached | ||
370 | * to PHB directly. Otherwise, we have to associate the | ||
371 | * PE with its parent. | ||
372 | */ | ||
373 | parent = eeh_pe_get_parent(edev); | ||
374 | if (!parent) { | ||
375 | parent = eeh_phb_pe_get(edev->phb); | ||
376 | if (!parent) { | ||
377 | eeh_unlock(); | ||
378 | pr_err("%s: No PHB PE is found (PHB Domain=%d)\n", | ||
379 | __func__, edev->phb->global_number); | ||
380 | edev->pe = NULL; | ||
381 | kfree(pe); | ||
382 | return -EEXIST; | ||
383 | } | ||
384 | } | ||
385 | pe->parent = parent; | ||
386 | |||
387 | /* | ||
388 | * Put the newly created PE into the child list and | ||
389 | * link the EEH device accordingly. | ||
390 | */ | ||
391 | list_add_tail(&pe->child, &parent->child_list); | ||
392 | list_add_tail(&edev->list, &pe->edevs); | ||
393 | edev->pe = pe; | ||
394 | eeh_unlock(); | ||
395 | pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", | ||
396 | edev->dn->full_name, pe->addr, pe->parent->addr); | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | /** | ||
402 | * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE | ||
403 | * @edev: EEH device | ||
404 | * @purge_pe: remove PE or not | ||
405 | * | ||
406 | * The PE hierarchy tree might be changed when doing PCI hotplug. | ||
407 | * Also, the PCI devices or buses could be removed from the system | ||
408 | * during EEH recovery. So we have to call the function remove the | ||
409 | * corresponding PE accordingly if necessary. | ||
410 | */ | ||
411 | int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) | ||
412 | { | ||
413 | struct eeh_pe *pe, *parent, *child; | ||
414 | int cnt; | ||
415 | |||
416 | if (!edev->pe) { | ||
417 | pr_warning("%s: No PE found for EEH device %s\n", | ||
418 | __func__, edev->dn->full_name); | ||
419 | return -EEXIST; | ||
420 | } | ||
421 | |||
422 | eeh_lock(); | ||
423 | |||
424 | /* Remove the EEH device */ | ||
425 | pe = edev->pe; | ||
426 | edev->pe = NULL; | ||
427 | list_del(&edev->list); | ||
428 | |||
429 | /* | ||
430 | * Check if the parent PE includes any EEH devices. | ||
431 | * If not, we should delete that. Also, we should | ||
432 | * delete the parent PE if it doesn't have associated | ||
433 | * child PEs and EEH devices. | ||
434 | */ | ||
435 | while (1) { | ||
436 | parent = pe->parent; | ||
437 | if (pe->type & EEH_PE_PHB) | ||
438 | break; | ||
439 | |||
440 | if (purge_pe) { | ||
441 | if (list_empty(&pe->edevs) && | ||
442 | list_empty(&pe->child_list)) { | ||
443 | list_del(&pe->child); | ||
444 | kfree(pe); | ||
445 | } else { | ||
446 | break; | ||
447 | } | ||
448 | } else { | ||
449 | if (list_empty(&pe->edevs)) { | ||
450 | cnt = 0; | ||
451 | list_for_each_entry(child, &pe->child_list, child) { | ||
452 | if (!(child->type & EEH_PE_INVALID)) { | ||
453 | cnt++; | ||
454 | break; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | if (!cnt) | ||
459 | pe->type |= EEH_PE_INVALID; | ||
460 | else | ||
461 | break; | ||
462 | } | ||
463 | } | ||
464 | |||
465 | pe = parent; | ||
466 | } | ||
467 | |||
468 | eeh_unlock(); | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * __eeh_pe_state_mark - Mark the state for the PE | ||
475 | * @data: EEH PE | ||
476 | * @flag: state | ||
477 | * | ||
478 | * The function is used to mark the indicated state for the given | ||
479 | * PE. Also, the associated PCI devices will be put into IO frozen | ||
480 | * state as well. | ||
481 | */ | ||
482 | static void *__eeh_pe_state_mark(void *data, void *flag) | ||
483 | { | ||
484 | struct eeh_pe *pe = (struct eeh_pe *)data; | ||
485 | int state = *((int *)flag); | ||
486 | struct eeh_dev *tmp; | ||
487 | struct pci_dev *pdev; | ||
488 | |||
489 | /* | ||
490 | * Mark the PE with the indicated state. Also, | ||
491 | * the associated PCI device will be put into | ||
492 | * I/O frozen state to avoid I/O accesses from | ||
493 | * the PCI device driver. | ||
494 | */ | ||
495 | pe->state |= state; | ||
496 | eeh_pe_for_each_dev(pe, tmp) { | ||
497 | pdev = eeh_dev_to_pci_dev(tmp); | ||
498 | if (pdev) | ||
499 | pdev->error_state = pci_channel_io_frozen; | ||
500 | } | ||
501 | |||
502 | return NULL; | ||
503 | } | ||
504 | |||
505 | /** | ||
506 | * eeh_pe_state_mark - Mark specified state for PE and its associated device | ||
507 | * @pe: EEH PE | ||
508 | * | ||
509 | * EEH error affects the current PE and its child PEs. The function | ||
510 | * is used to mark appropriate state for the affected PEs and the | ||
511 | * associated devices. | ||
512 | */ | ||
513 | void eeh_pe_state_mark(struct eeh_pe *pe, int state) | ||
514 | { | ||
515 | eeh_lock(); | ||
516 | eeh_pe_traverse(pe, __eeh_pe_state_mark, &state); | ||
517 | eeh_unlock(); | ||
518 | } | ||
519 | |||
520 | /** | ||
521 | * __eeh_pe_state_clear - Clear state for the PE | ||
522 | * @data: EEH PE | ||
523 | * @flag: state | ||
524 | * | ||
525 | * The function is used to clear the indicated state from the | ||
526 | * given PE. Besides, we also clear the check count of the PE | ||
527 | * as well. | ||
528 | */ | ||
529 | static void *__eeh_pe_state_clear(void *data, void *flag) | ||
530 | { | ||
531 | struct eeh_pe *pe = (struct eeh_pe *)data; | ||
532 | int state = *((int *)flag); | ||
533 | |||
534 | pe->state &= ~state; | ||
535 | pe->check_count = 0; | ||
536 | |||
537 | return NULL; | ||
538 | } | ||
539 | |||
540 | /** | ||
541 | * eeh_pe_state_clear - Clear state for the PE and its children | ||
542 | * @pe: PE | ||
543 | * @state: state to be cleared | ||
544 | * | ||
545 | * When the PE and its children has been recovered from error, | ||
546 | * we need clear the error state for that. The function is used | ||
547 | * for the purpose. | ||
548 | */ | ||
549 | void eeh_pe_state_clear(struct eeh_pe *pe, int state) | ||
550 | { | ||
551 | eeh_lock(); | ||
552 | eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); | ||
553 | eeh_unlock(); | ||
554 | } | ||
555 | |||
556 | /** | ||
557 | * eeh_restore_one_device_bars - Restore the Base Address Registers for one device | ||
558 | * @data: EEH device | ||
559 | * @flag: Unused | ||
560 | * | ||
561 | * Loads the PCI configuration space base address registers, | ||
562 | * the expansion ROM base address, the latency timer, and etc. | ||
563 | * from the saved values in the device node. | ||
564 | */ | ||
565 | static void *eeh_restore_one_device_bars(void *data, void *flag) | ||
566 | { | ||
567 | int i; | ||
568 | u32 cmd; | ||
569 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
570 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
571 | |||
572 | for (i = 4; i < 10; i++) | ||
573 | eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); | ||
574 | /* 12 == Expansion ROM Address */ | ||
575 | eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); | ||
576 | |||
577 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) | ||
578 | #define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) | ||
579 | |||
580 | eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, | ||
581 | SAVED_BYTE(PCI_CACHE_LINE_SIZE)); | ||
582 | eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, | ||
583 | SAVED_BYTE(PCI_LATENCY_TIMER)); | ||
584 | |||
585 | /* max latency, min grant, interrupt pin and line */ | ||
586 | eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]); | ||
587 | |||
588 | /* | ||
589 | * Restore PERR & SERR bits, some devices require it, | ||
590 | * don't touch the other command bits | ||
591 | */ | ||
592 | eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd); | ||
593 | if (edev->config_space[1] & PCI_COMMAND_PARITY) | ||
594 | cmd |= PCI_COMMAND_PARITY; | ||
595 | else | ||
596 | cmd &= ~PCI_COMMAND_PARITY; | ||
597 | if (edev->config_space[1] & PCI_COMMAND_SERR) | ||
598 | cmd |= PCI_COMMAND_SERR; | ||
599 | else | ||
600 | cmd &= ~PCI_COMMAND_SERR; | ||
601 | eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); | ||
602 | |||
603 | return NULL; | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * eeh_pe_restore_bars - Restore the PCI config space info | ||
608 | * @pe: EEH PE | ||
609 | * | ||
610 | * This routine performs a recursive walk to the children | ||
611 | * of this device as well. | ||
612 | */ | ||
613 | void eeh_pe_restore_bars(struct eeh_pe *pe) | ||
614 | { | ||
615 | /* | ||
616 | * We needn't take the EEH lock since eeh_pe_dev_traverse() | ||
617 | * will take that. | ||
618 | */ | ||
619 | eeh_pe_dev_traverse(pe, eeh_restore_one_device_bars, NULL); | ||
620 | } | ||
621 | |||
622 | /** | ||
623 | * eeh_pe_bus_get - Retrieve PCI bus according to the given PE | ||
624 | * @pe: EEH PE | ||
625 | * | ||
626 | * Retrieve the PCI bus according to the given PE. Basically, | ||
627 | * there're 3 types of PEs: PHB/Bus/Device. For PHB PE, the | ||
628 | * primary PCI bus will be retrieved. The parent bus will be | ||
629 | * returned for BUS PE. However, we don't have associated PCI | ||
630 | * bus for DEVICE PE. | ||
631 | */ | ||
632 | struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) | ||
633 | { | ||
634 | struct pci_bus *bus = NULL; | ||
635 | struct eeh_dev *edev; | ||
636 | struct pci_dev *pdev; | ||
637 | |||
638 | eeh_lock(); | ||
639 | |||
640 | if (pe->type & EEH_PE_PHB) { | ||
641 | bus = pe->phb->bus; | ||
642 | } else if (pe->type & EEH_PE_BUS || | ||
643 | pe->type & EEH_PE_DEVICE) { | ||
644 | edev = list_first_entry(&pe->edevs, struct eeh_dev, list); | ||
645 | pdev = eeh_dev_to_pci_dev(edev); | ||
646 | if (pdev) | ||
647 | bus = pdev->bus; | ||
648 | } | ||
649 | |||
650 | eeh_unlock(); | ||
651 | |||
652 | return bus; | ||
653 | } | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c deleted file mode 100644 index d37708360f2e..000000000000 --- a/arch/powerpc/platforms/pseries/eeh_sysfs.c +++ /dev/null | |||
@@ -1,75 +0,0 @@ | |||
1 | /* | ||
2 | * Sysfs entries for PCI Error Recovery for PAPR-compliant platform. | ||
3 | * Copyright IBM Corporation 2007 | ||
4 | * Copyright Linas Vepstas <linas@austin.ibm.com> 2007 | ||
5 | * | ||
6 | * All rights reserved. | ||
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 (at | ||
11 | * your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
16 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | * Send comments and feedback to Linas Vepstas <linas@austin.ibm.com> | ||
24 | */ | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/stat.h> | ||
27 | #include <asm/ppc-pci.h> | ||
28 | #include <asm/pci-bridge.h> | ||
29 | |||
30 | /** | ||
31 | * EEH_SHOW_ATTR -- Create sysfs entry for eeh statistic | ||
32 | * @_name: name of file in sysfs directory | ||
33 | * @_memb: name of member in struct pci_dn to access | ||
34 | * @_format: printf format for display | ||
35 | * | ||
36 | * All of the attributes look very similar, so just | ||
37 | * auto-gen a cut-n-paste routine to display them. | ||
38 | */ | ||
39 | #define EEH_SHOW_ATTR(_name,_memb,_format) \ | ||
40 | static ssize_t eeh_show_##_name(struct device *dev, \ | ||
41 | struct device_attribute *attr, char *buf) \ | ||
42 | { \ | ||
43 | struct pci_dev *pdev = to_pci_dev(dev); \ | ||
44 | struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev); \ | ||
45 | \ | ||
46 | if (!edev) \ | ||
47 | return 0; \ | ||
48 | \ | ||
49 | return sprintf(buf, _format "\n", edev->_memb); \ | ||
50 | } \ | ||
51 | static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); | ||
52 | |||
53 | EEH_SHOW_ATTR(eeh_mode, mode, "0x%x"); | ||
54 | EEH_SHOW_ATTR(eeh_config_addr, config_addr, "0x%x"); | ||
55 | EEH_SHOW_ATTR(eeh_pe_config_addr, pe_config_addr, "0x%x"); | ||
56 | |||
57 | void eeh_sysfs_add_device(struct pci_dev *pdev) | ||
58 | { | ||
59 | int rc=0; | ||
60 | |||
61 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode); | ||
62 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr); | ||
63 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); | ||
64 | |||
65 | if (rc) | ||
66 | printk(KERN_WARNING "EEH: Unable to create sysfs entries\n"); | ||
67 | } | ||
68 | |||
69 | void eeh_sysfs_remove_device(struct pci_dev *pdev) | ||
70 | { | ||
71 | device_remove_file(&pdev->dev, &dev_attr_eeh_mode); | ||
72 | device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr); | ||
73 | device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); | ||
74 | } | ||
75 | |||
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index c91b22be9288..efe61374f6ea 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c | |||
@@ -64,91 +64,6 @@ pcibios_find_pci_bus(struct device_node *dn) | |||
64 | } | 64 | } |
65 | EXPORT_SYMBOL_GPL(pcibios_find_pci_bus); | 65 | EXPORT_SYMBOL_GPL(pcibios_find_pci_bus); |
66 | 66 | ||
67 | /** | ||
68 | * __pcibios_remove_pci_devices - remove all devices under this bus | ||
69 | * @bus: the indicated PCI bus | ||
70 | * @purge_pe: destroy the PE on removal of PCI devices | ||
71 | * | ||
72 | * Remove all of the PCI devices under this bus both from the | ||
73 | * linux pci device tree, and from the powerpc EEH address cache. | ||
74 | * By default, the corresponding PE will be destroied during the | ||
75 | * normal PCI hotplug path. For PCI hotplug during EEH recovery, | ||
76 | * the corresponding PE won't be destroied and deallocated. | ||
77 | */ | ||
78 | void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe) | ||
79 | { | ||
80 | struct pci_dev *dev, *tmp; | ||
81 | struct pci_bus *child_bus; | ||
82 | |||
83 | /* First go down child busses */ | ||
84 | list_for_each_entry(child_bus, &bus->children, node) | ||
85 | __pcibios_remove_pci_devices(child_bus, purge_pe); | ||
86 | |||
87 | pr_debug("PCI: Removing devices on bus %04x:%02x\n", | ||
88 | pci_domain_nr(bus), bus->number); | ||
89 | list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { | ||
90 | pr_debug(" * Removing %s...\n", pci_name(dev)); | ||
91 | eeh_remove_bus_device(dev, purge_pe); | ||
92 | pci_stop_and_remove_bus_device(dev); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * pcibios_remove_pci_devices - remove all devices under this bus | ||
98 | * | ||
99 | * Remove all of the PCI devices under this bus both from the | ||
100 | * linux pci device tree, and from the powerpc EEH address cache. | ||
101 | */ | ||
102 | void pcibios_remove_pci_devices(struct pci_bus *bus) | ||
103 | { | ||
104 | __pcibios_remove_pci_devices(bus, 1); | ||
105 | } | ||
106 | EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); | ||
107 | |||
108 | /** | ||
109 | * pcibios_add_pci_devices - adds new pci devices to bus | ||
110 | * | ||
111 | * This routine will find and fixup new pci devices under | ||
112 | * the indicated bus. This routine presumes that there | ||
113 | * might already be some devices under this bridge, so | ||
114 | * it carefully tries to add only new devices. (And that | ||
115 | * is how this routine differs from other, similar pcibios | ||
116 | * routines.) | ||
117 | */ | ||
118 | void pcibios_add_pci_devices(struct pci_bus * bus) | ||
119 | { | ||
120 | int slotno, num, mode, pass, max; | ||
121 | struct pci_dev *dev; | ||
122 | struct device_node *dn = pci_bus_to_OF_node(bus); | ||
123 | |||
124 | eeh_add_device_tree_early(dn); | ||
125 | |||
126 | mode = PCI_PROBE_NORMAL; | ||
127 | if (ppc_md.pci_probe_mode) | ||
128 | mode = ppc_md.pci_probe_mode(bus); | ||
129 | |||
130 | if (mode == PCI_PROBE_DEVTREE) { | ||
131 | /* use ofdt-based probe */ | ||
132 | of_rescan_bus(dn, bus); | ||
133 | } else if (mode == PCI_PROBE_NORMAL) { | ||
134 | /* use legacy probe */ | ||
135 | slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); | ||
136 | num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); | ||
137 | if (!num) | ||
138 | return; | ||
139 | pcibios_setup_bus_devices(bus); | ||
140 | max = bus->busn_res.start; | ||
141 | for (pass=0; pass < 2; pass++) | ||
142 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
143 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | ||
144 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) | ||
145 | max = pci_scan_bridge(bus, dev, max, pass); | ||
146 | } | ||
147 | } | ||
148 | pcibios_finish_adding_to_bus(bus); | ||
149 | } | ||
150 | EXPORT_SYMBOL_GPL(pcibios_add_pci_devices); | ||
151 | |||
152 | struct pci_controller *init_phb_dynamic(struct device_node *dn) | 67 | struct pci_controller *init_phb_dynamic(struct device_node *dn) |
153 | { | 68 | { |
154 | struct pci_controller *phb; | 69 | struct pci_controller *phb; |