aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/eeh.h3
-rw-r--r--arch/powerpc/include/asm/ppc-pci.h1
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c79
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pe.c94
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);
171int __devinit eeh_phb_pe_create(struct pci_controller *phb); 171int __devinit eeh_phb_pe_create(struct pci_controller *phb);
172int eeh_add_to_parent_pe(struct eeh_dev *edev); 172int eeh_add_to_parent_pe(struct eeh_dev *edev);
173int eeh_rmv_from_parent_pe(struct eeh_dev *edev); 173int eeh_rmv_from_parent_pe(struct eeh_dev *edev);
174void *eeh_pe_dev_traverse(struct eeh_pe *root,
175 eeh_traverse_func fn, void *flag);
176void eeh_pe_restore_bars(struct eeh_pe *pe);
174 177
175void * __devinit eeh_dev_init(struct device_node *dn, void *data); 178void * __devinit eeh_dev_init(struct device_node *dn, void *data);
176void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb); 179void __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);
54void eeh_slot_error_detail(struct eeh_dev *edev, int severity); 54void eeh_slot_error_detail(struct eeh_dev *edev, int severity);
55int eeh_pci_enable(struct eeh_dev *edev, int function); 55int eeh_pci_enable(struct eeh_dev *edev, int function);
56int eeh_reset_pe(struct eeh_dev *); 56int eeh_reset_pe(struct eeh_dev *);
57void eeh_restore_bars(struct eeh_dev *);
58int rtas_write_config(struct pci_dn *, int where, int size, u32 val); 57int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
59int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); 58int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
60void eeh_pe_state_mark(struct eeh_pe *pe, int state); 59void 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 */
629static 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 */
679void 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 */
183void *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 */
512static 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 */
560void eeh_pe_restore_bars(struct eeh_pe *pe)
561{
562 eeh_pe_dev_traverse(pe, eeh_restore_one_device_bars, NULL);
563}