diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/eeh.h | 3 | ||||
-rw-r--r-- | arch/powerpc/include/asm/ppc-pci.h | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh.c | 79 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_pe.c | 94 |
4 files changed, 97 insertions, 80 deletions
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 5e45a1c5c9e8..629fb27c093e 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h | |||
@@ -171,6 +171,9 @@ typedef void *(*eeh_traverse_func)(void *data, void *flag); | |||
171 | int __devinit eeh_phb_pe_create(struct pci_controller *phb); | 171 | int __devinit eeh_phb_pe_create(struct pci_controller *phb); |
172 | int eeh_add_to_parent_pe(struct eeh_dev *edev); | 172 | int eeh_add_to_parent_pe(struct eeh_dev *edev); |
173 | int eeh_rmv_from_parent_pe(struct eeh_dev *edev); | 173 | int eeh_rmv_from_parent_pe(struct eeh_dev *edev); |
174 | void *eeh_pe_dev_traverse(struct eeh_pe *root, | ||
175 | eeh_traverse_func fn, void *flag); | ||
176 | void eeh_pe_restore_bars(struct eeh_pe *pe); | ||
174 | 177 | ||
175 | void * __devinit eeh_dev_init(struct device_node *dn, void *data); | 178 | void * __devinit eeh_dev_init(struct device_node *dn, void *data); |
176 | void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb); | 179 | void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb); |
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h index 3e301b14e09f..5cbe3f2a7e80 100644 --- a/arch/powerpc/include/asm/ppc-pci.h +++ b/arch/powerpc/include/asm/ppc-pci.h | |||
@@ -54,7 +54,6 @@ struct pci_dev *pci_addr_cache_get_device(unsigned long addr); | |||
54 | void eeh_slot_error_detail(struct eeh_dev *edev, int severity); | 54 | void eeh_slot_error_detail(struct eeh_dev *edev, int severity); |
55 | int eeh_pci_enable(struct eeh_dev *edev, int function); | 55 | int eeh_pci_enable(struct eeh_dev *edev, int function); |
56 | int eeh_reset_pe(struct eeh_dev *); | 56 | int eeh_reset_pe(struct eeh_dev *); |
57 | void eeh_restore_bars(struct eeh_dev *); | ||
58 | int rtas_write_config(struct pci_dn *, int where, int size, u32 val); | 57 | int rtas_write_config(struct pci_dn *, int where, int size, u32 val); |
59 | int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); | 58 | int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); |
60 | void eeh_pe_state_mark(struct eeh_pe *pe, int state); | 59 | void eeh_pe_state_mark(struct eeh_pe *pe, int state); |
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 3c8658ea13f2..b5fcecb06731 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -610,85 +610,6 @@ int eeh_reset_pe(struct eeh_dev *edev) | |||
610 | return -1; | 610 | return -1; |
611 | } | 611 | } |
612 | 612 | ||
613 | /** Save and restore of PCI BARs | ||
614 | * | ||
615 | * Although firmware will set up BARs during boot, it doesn't | ||
616 | * set up device BAR's after a device reset, although it will, | ||
617 | * if requested, set up bridge configuration. Thus, we need to | ||
618 | * configure the PCI devices ourselves. | ||
619 | */ | ||
620 | |||
621 | /** | ||
622 | * eeh_restore_one_device_bars - Restore the Base Address Registers for one device | ||
623 | * @edev: PCI device associated EEH device | ||
624 | * | ||
625 | * Loads the PCI configuration space base address registers, | ||
626 | * the expansion ROM base address, the latency timer, and etc. | ||
627 | * from the saved values in the device node. | ||
628 | */ | ||
629 | static inline void eeh_restore_one_device_bars(struct eeh_dev *edev) | ||
630 | { | ||
631 | int i; | ||
632 | u32 cmd; | ||
633 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
634 | |||
635 | if (!edev->phb) | ||
636 | return; | ||
637 | |||
638 | for (i=4; i<10; i++) { | ||
639 | eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); | ||
640 | } | ||
641 | |||
642 | /* 12 == Expansion ROM Address */ | ||
643 | eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); | ||
644 | |||
645 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) | ||
646 | #define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) | ||
647 | |||
648 | eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, | ||
649 | SAVED_BYTE(PCI_CACHE_LINE_SIZE)); | ||
650 | |||
651 | eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, | ||
652 | SAVED_BYTE(PCI_LATENCY_TIMER)); | ||
653 | |||
654 | /* max latency, min grant, interrupt pin and line */ | ||
655 | eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]); | ||
656 | |||
657 | /* Restore PERR & SERR bits, some devices require it, | ||
658 | * don't touch the other command bits | ||
659 | */ | ||
660 | eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd); | ||
661 | if (edev->config_space[1] & PCI_COMMAND_PARITY) | ||
662 | cmd |= PCI_COMMAND_PARITY; | ||
663 | else | ||
664 | cmd &= ~PCI_COMMAND_PARITY; | ||
665 | if (edev->config_space[1] & PCI_COMMAND_SERR) | ||
666 | cmd |= PCI_COMMAND_SERR; | ||
667 | else | ||
668 | cmd &= ~PCI_COMMAND_SERR; | ||
669 | eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); | ||
670 | } | ||
671 | |||
672 | /** | ||
673 | * eeh_restore_bars - Restore the PCI config space info | ||
674 | * @edev: EEH device | ||
675 | * | ||
676 | * This routine performs a recursive walk to the children | ||
677 | * of this device as well. | ||
678 | */ | ||
679 | void eeh_restore_bars(struct eeh_dev *edev) | ||
680 | { | ||
681 | struct device_node *dn; | ||
682 | if (!edev) | ||
683 | return; | ||
684 | |||
685 | if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code)) | ||
686 | eeh_restore_one_device_bars(edev); | ||
687 | |||
688 | for_each_child_of_node(eeh_dev_to_of_node(edev), dn) | ||
689 | eeh_restore_bars(of_node_to_eeh_dev(dn)); | ||
690 | } | ||
691 | |||
692 | /** | 613 | /** |
693 | * eeh_save_bars - Save device bars | 614 | * eeh_save_bars - Save device bars |
694 | * @edev: PCI device associated EEH device | 615 | * @edev: PCI device associated EEH device |
diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c index 0dac1b69582d..2b7e85b804a4 100644 --- a/arch/powerpc/platforms/pseries/eeh_pe.c +++ b/arch/powerpc/platforms/pseries/eeh_pe.c | |||
@@ -172,6 +172,38 @@ static void *eeh_pe_traverse(struct eeh_pe *root, | |||
172 | } | 172 | } |
173 | 173 | ||
174 | /** | 174 | /** |
175 | * eeh_pe_dev_traverse - Traverse the devices from the PE | ||
176 | * @root: EEH PE | ||
177 | * @fn: function callback | ||
178 | * @flag: extra parameter to callback | ||
179 | * | ||
180 | * The function is used to traverse the devices of the specified | ||
181 | * PE and its child PEs. | ||
182 | */ | ||
183 | void *eeh_pe_dev_traverse(struct eeh_pe *root, | ||
184 | eeh_traverse_func fn, void *flag) | ||
185 | { | ||
186 | struct eeh_pe *pe; | ||
187 | struct eeh_dev *edev; | ||
188 | void *ret; | ||
189 | |||
190 | if (!root) { | ||
191 | pr_warning("%s: Invalid PE %p\n", __func__, root); | ||
192 | return NULL; | ||
193 | } | ||
194 | |||
195 | /* Traverse root PE */ | ||
196 | for (pe = root; pe; pe = eeh_pe_next(pe, root)) { | ||
197 | eeh_pe_for_each_dev(pe, edev) { | ||
198 | ret = fn(edev, flag); | ||
199 | if (ret) return ret; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | return NULL; | ||
204 | } | ||
205 | |||
206 | /** | ||
175 | * __eeh_pe_get - Check the PE address | 207 | * __eeh_pe_get - Check the PE address |
176 | * @data: EEH PE | 208 | * @data: EEH PE |
177 | * @flag: EEH device | 209 | * @flag: EEH device |
@@ -467,3 +499,65 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state) | |||
467 | { | 499 | { |
468 | eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); | 500 | eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); |
469 | } | 501 | } |
502 | |||
503 | /** | ||
504 | * eeh_restore_one_device_bars - Restore the Base Address Registers for one device | ||
505 | * @data: EEH device | ||
506 | * @flag: Unused | ||
507 | * | ||
508 | * Loads the PCI configuration space base address registers, | ||
509 | * the expansion ROM base address, the latency timer, and etc. | ||
510 | * from the saved values in the device node. | ||
511 | */ | ||
512 | static void *eeh_restore_one_device_bars(void *data, void *flag) | ||
513 | { | ||
514 | int i; | ||
515 | u32 cmd; | ||
516 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
517 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
518 | |||
519 | for (i = 4; i < 10; i++) | ||
520 | eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); | ||
521 | /* 12 == Expansion ROM Address */ | ||
522 | eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); | ||
523 | |||
524 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) | ||
525 | #define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) | ||
526 | |||
527 | eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, | ||
528 | SAVED_BYTE(PCI_CACHE_LINE_SIZE)); | ||
529 | eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, | ||
530 | SAVED_BYTE(PCI_LATENCY_TIMER)); | ||
531 | |||
532 | /* max latency, min grant, interrupt pin and line */ | ||
533 | eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]); | ||
534 | |||
535 | /* | ||
536 | * Restore PERR & SERR bits, some devices require it, | ||
537 | * don't touch the other command bits | ||
538 | */ | ||
539 | eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd); | ||
540 | if (edev->config_space[1] & PCI_COMMAND_PARITY) | ||
541 | cmd |= PCI_COMMAND_PARITY; | ||
542 | else | ||
543 | cmd &= ~PCI_COMMAND_PARITY; | ||
544 | if (edev->config_space[1] & PCI_COMMAND_SERR) | ||
545 | cmd |= PCI_COMMAND_SERR; | ||
546 | else | ||
547 | cmd &= ~PCI_COMMAND_SERR; | ||
548 | eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); | ||
549 | |||
550 | return NULL; | ||
551 | } | ||
552 | |||
553 | /** | ||
554 | * eeh_pe_restore_bars - Restore the PCI config space info | ||
555 | * @pe: EEH PE | ||
556 | * | ||
557 | * This routine performs a recursive walk to the children | ||
558 | * of this device as well. | ||
559 | */ | ||
560 | void eeh_pe_restore_bars(struct eeh_pe *pe) | ||
561 | { | ||
562 | eeh_pe_dev_traverse(pe, eeh_restore_one_device_bars, NULL); | ||
563 | } | ||