Commit | Line | Data |
---|---|---|
55037d17 GS |
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 | */ | |
cad5cef6 | 69 | int eeh_phb_pe_create(struct pci_controller *phb) |
55037d17 GS |
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 | ||
55037d17 GS |
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 | */ | |
7844663a | 108 | if ((pe->type & EEH_PE_PHB) && pe->phb == phb) |
55037d17 | 109 | return pe; |
55037d17 GS |
110 | } |
111 | ||
55037d17 GS |
112 | return NULL; |
113 | } | |
22f4ab12 GS |
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 | ||
9e6d2cf6 GS |
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 | ||
ea81245c GS |
188 | eeh_lock(); |
189 | ||
9e6d2cf6 GS |
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); | |
ea81245c GS |
194 | if (ret) { |
195 | eeh_unlock(); | |
196 | return ret; | |
197 | } | |
9e6d2cf6 GS |
198 | } |
199 | } | |
200 | ||
ea81245c GS |
201 | eeh_unlock(); |
202 | ||
9e6d2cf6 GS |
203 | return NULL; |
204 | } | |
205 | ||
22f4ab12 GS |
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 */ | |
5efc3ad7 | 222 | if (pe->type & EEH_PE_PHB) |
22f4ab12 GS |
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 | ||
22f4ab12 | 254 | pe = eeh_pe_traverse(root, __eeh_pe_get, edev); |
22f4ab12 GS |
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 | } | |
9b84348c GS |
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 | ||
ea81245c GS |
308 | eeh_lock(); |
309 | ||
9b84348c GS |
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); | |
5efc3ad7 | 317 | if (pe && !(pe->type & EEH_PE_INVALID)) { |
9b84348c | 318 | if (!edev->pe_config_addr) { |
ea81245c | 319 | eeh_unlock(); |
9b84348c GS |
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); | |
ea81245c | 331 | eeh_unlock(); |
9b84348c GS |
332 | pr_debug("EEH: Add %s to Bus PE#%x\n", |
333 | edev->dn->full_name, pe->addr); | |
334 | ||
5efc3ad7 GS |
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 | } | |
ea81245c | 350 | eeh_unlock(); |
5efc3ad7 GS |
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 | ||
9b84348c GS |
354 | return 0; |
355 | } | |
356 | ||
357 | /* Create a new EEH PE */ | |
358 | pe = eeh_pe_alloc(edev->phb, EEH_PE_DEVICE); | |
359 | if (!pe) { | |
ea81245c | 360 | eeh_unlock(); |
9b84348c GS |
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) { | |
ea81245c | 377 | eeh_unlock(); |
9b84348c GS |
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; | |
ea81245c | 394 | eeh_unlock(); |
9b84348c GS |
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 | } | |
82e8882f GS |
400 | |
401 | /** | |
402 | * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE | |
403 | * @edev: EEH device | |
20ee6a97 | 404 | * @purge_pe: remove PE or not |
82e8882f GS |
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 | */ | |
20ee6a97 | 411 | int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) |
82e8882f | 412 | { |
5efc3ad7 GS |
413 | struct eeh_pe *pe, *parent, *child; |
414 | int cnt; | |
82e8882f GS |
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 | ||
ea81245c GS |
422 | eeh_lock(); |
423 | ||
82e8882f GS |
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; | |
5efc3ad7 | 437 | if (pe->type & EEH_PE_PHB) |
82e8882f GS |
438 | break; |
439 | ||
20ee6a97 GS |
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; | |
5efc3ad7 | 447 | } |
20ee6a97 GS |
448 | } else { |
449 | if (list_empty(&pe->edevs)) { | |
450 | cnt = 0; | |
451 | list_for_each_entry(child, &pe->child_list, child) { | |
e716e014 | 452 | if (!(child->type & EEH_PE_INVALID)) { |
20ee6a97 GS |
453 | cnt++; |
454 | break; | |
455 | } | |
456 | } | |
5efc3ad7 | 457 | |
20ee6a97 GS |
458 | if (!cnt) |
459 | pe->type |= EEH_PE_INVALID; | |
460 | else | |
461 | break; | |
462 | } | |
82e8882f GS |
463 | } |
464 | ||
465 | pe = parent; | |
466 | } | |
467 | ||
ea81245c GS |
468 | eeh_unlock(); |
469 | ||
82e8882f GS |
470 | return 0; |
471 | } | |
5b663529 GS |
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 | { | |
ea81245c | 515 | eeh_lock(); |
5b663529 | 516 | eeh_pe_traverse(pe, __eeh_pe_state_mark, &state); |
ea81245c | 517 | eeh_unlock(); |
5b663529 GS |
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 | { | |
ea81245c | 551 | eeh_lock(); |
5b663529 | 552 | eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); |
ea81245c | 553 | eeh_unlock(); |
5b663529 | 554 | } |
9e6d2cf6 GS |
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 | { | |
ea81245c GS |
615 | /* |
616 | * We needn't take the EEH lock since eeh_pe_dev_traverse() | |
617 | * will take that. | |
618 | */ | |
9e6d2cf6 GS |
619 | eeh_pe_dev_traverse(pe, eeh_restore_one_device_bars, NULL); |
620 | } | |
9b3c76f0 GS |
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 | ||
ea81245c GS |
638 | eeh_lock(); |
639 | ||
5efc3ad7 | 640 | if (pe->type & EEH_PE_PHB) { |
9b3c76f0 | 641 | bus = pe->phb->bus; |
5fb62169 GS |
642 | } else if (pe->type & EEH_PE_BUS || |
643 | pe->type & EEH_PE_DEVICE) { | |
9b3c76f0 GS |
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 | ||
ea81245c GS |
650 | eeh_unlock(); |
651 | ||
9b3c76f0 GS |
652 | return bus; |
653 | } |