aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c115
-rw-r--r--include/asm-powerpc/ppc-pci.h23
2 files changed, 137 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index a06c91a4852b..b760836bb9d1 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -77,6 +77,9 @@
77 */ 77 */
78#define EEH_MAX_FAILS 100000 78#define EEH_MAX_FAILS 100000
79 79
80/* Misc forward declaraions */
81static void eeh_save_bars(struct pci_dev * pdev, struct pci_dn *pdn);
82
80/* RTAS tokens */ 83/* RTAS tokens */
81static int ibm_set_eeh_option; 84static int ibm_set_eeh_option;
82static int ibm_set_slot_reset; 85static int ibm_set_slot_reset;
@@ -366,6 +369,7 @@ static void pci_addr_cache_remove_device(struct pci_dev *dev)
366 */ 369 */
367void __init pci_addr_cache_build(void) 370void __init pci_addr_cache_build(void)
368{ 371{
372 struct device_node *dn;
369 struct pci_dev *dev = NULL; 373 struct pci_dev *dev = NULL;
370 374
371 if (!eeh_subsystem_enabled) 375 if (!eeh_subsystem_enabled)
@@ -379,6 +383,10 @@ void __init pci_addr_cache_build(void)
379 continue; 383 continue;
380 } 384 }
381 pci_addr_cache_insert_device(dev); 385 pci_addr_cache_insert_device(dev);
386
387 /* Save the BAR's; firmware doesn't restore these after EEH reset */
388 dn = pci_device_to_OF_node(dev);
389 eeh_save_bars(dev, PCI_DN(dn));
382 } 390 }
383 391
384#ifdef DEBUG 392#ifdef DEBUG
@@ -775,6 +783,108 @@ rtas_set_slot_reset(struct pci_dn *pdn)
775 } 783 }
776} 784}
777 785
786/* ------------------------------------------------------- */
787/** Save and restore of PCI BARs
788 *
789 * Although firmware will set up BARs during boot, it doesn't
790 * set up device BAR's after a device reset, although it will,
791 * if requested, set up bridge configuration. Thus, we need to
792 * configure the PCI devices ourselves.
793 */
794
795/**
796 * __restore_bars - Restore the Base Address Registers
797 * Loads the PCI configuration space base address registers,
798 * the expansion ROM base address, the latency timer, and etc.
799 * from the saved values in the device node.
800 */
801static inline void __restore_bars (struct pci_dn *pdn)
802{
803 int i;
804
805 if (NULL==pdn->phb) return;
806 for (i=4; i<10; i++) {
807 rtas_write_config(pdn, i*4, 4, pdn->config_space[i]);
808 }
809
810 /* 12 == Expansion ROM Address */
811 rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]);
812
813#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
814#define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)])
815
816 rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1,
817 SAVED_BYTE(PCI_CACHE_LINE_SIZE));
818
819 rtas_write_config (pdn, PCI_LATENCY_TIMER, 1,
820 SAVED_BYTE(PCI_LATENCY_TIMER));
821
822 /* max latency, min grant, interrupt pin and line */
823 rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]);
824}
825
826/**
827 * eeh_restore_bars - restore the PCI config space info
828 *
829 * This routine performs a recursive walk to the children
830 * of this device as well.
831 */
832void eeh_restore_bars(struct pci_dn *pdn)
833{
834 struct device_node *dn;
835 if (!pdn)
836 return;
837
838 if (! pdn->eeh_is_bridge)
839 __restore_bars (pdn);
840
841 dn = pdn->node->child;
842 while (dn) {
843 eeh_restore_bars (PCI_DN(dn));
844 dn = dn->sibling;
845 }
846}
847
848/**
849 * eeh_save_bars - save device bars
850 *
851 * Save the values of the device bars. Unlike the restore
852 * routine, this routine is *not* recursive. This is because
853 * PCI devices are added individuallly; but, for the restore,
854 * an entire slot is reset at a time.
855 */
856static void eeh_save_bars(struct pci_dev * pdev, struct pci_dn *pdn)
857{
858 int i;
859
860 if (!pdev || !pdn )
861 return;
862
863 for (i = 0; i < 16; i++)
864 pci_read_config_dword(pdev, i * 4, &pdn->config_space[i]);
865
866 if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
867 pdn->eeh_is_bridge = 1;
868}
869
870void
871rtas_configure_bridge(struct pci_dn *pdn)
872{
873 int token = rtas_token ("ibm,configure-bridge");
874 int rc;
875
876 if (token == RTAS_UNKNOWN_SERVICE)
877 return;
878 rc = rtas_call(token,3,1, NULL,
879 pdn->eeh_config_addr,
880 BUID_HI(pdn->phb->buid),
881 BUID_LO(pdn->phb->buid));
882 if (rc) {
883 printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n",
884 rc, pdn->node->full_name);
885 }
886}
887
778/* ------------------------------------------------------------- */ 888/* ------------------------------------------------------------- */
779/* The code below deals with enabling EEH for devices during the 889/* The code below deals with enabling EEH for devices during the
780 * early boot sequence. EEH must be enabled before any PCI probing 890 * early boot sequence. EEH must be enabled before any PCI probing
@@ -977,6 +1087,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_early);
977void eeh_add_device_late(struct pci_dev *dev) 1087void eeh_add_device_late(struct pci_dev *dev)
978{ 1088{
979 struct device_node *dn; 1089 struct device_node *dn;
1090 struct pci_dn *pdn;
980 1091
981 if (!dev || !eeh_subsystem_enabled) 1092 if (!dev || !eeh_subsystem_enabled)
982 return; 1093 return;
@@ -987,9 +1098,11 @@ void eeh_add_device_late(struct pci_dev *dev)
987 1098
988 pci_dev_get (dev); 1099 pci_dev_get (dev);
989 dn = pci_device_to_OF_node(dev); 1100 dn = pci_device_to_OF_node(dev);
990 PCI_DN(dn)->pcidev = dev; 1101 pdn = PCI_DN(dn);
1102 pdn->pcidev = dev;
991 1103
992 pci_addr_cache_insert_device (dev); 1104 pci_addr_cache_insert_device (dev);
1105 eeh_save_bars(dev, pdn);
993} 1106}
994EXPORT_SYMBOL_GPL(eeh_add_device_late); 1107EXPORT_SYMBOL_GPL(eeh_add_device_late);
995 1108
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index 930a606b4e35..d86c47872bea 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -64,6 +64,29 @@ extern int pci_read_irq_line(struct pci_dev *pci_dev);
64 */ 64 */
65void rtas_set_slot_reset (struct pci_dn *); 65void rtas_set_slot_reset (struct pci_dn *);
66 66
67/**
68 * eeh_restore_bars - Restore device configuration info.
69 *
70 * A reset of a PCI device will clear out its config space.
71 * This routines will restore the config space for this
72 * device, and is children, to values previously obtained
73 * from the firmware.
74 */
75void eeh_restore_bars(struct pci_dn *);
76
77/**
78 * rtas_configure_bridge -- firmware initialization of pci bridge
79 *
80 * Ask the firmware to configure all PCI bridges devices
81 * located behind the indicated node. Required after a
82 * pci device reset. Does essentially the same hing as
83 * eeh_restore_bars, but for brdges, and lets firmware
84 * do the work.
85 */
86void rtas_configure_bridge(struct pci_dn *);
87
88int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
89
67#endif 90#endif
68 91
69#endif /* _ASM_POWERPC_PPC_PCI_H */ 92#endif /* _ASM_POWERPC_PPC_PCI_H */