aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-27 15:48:37 -0400
committerPaul Mackerras <paulus@samba.org>2008-11-05 17:22:37 -0500
commit8b8da35804bb89eee23f9bcd5638e1f754bd4c91 (patch)
tree8ec1ba6ef03c88da5c37eec4825fff6524358b37 /arch/powerpc
parentab56ced9c57b66862c687f3158045d15133f02d6 (diff)
powerpc/pci: Split pcibios_fixup_bus() into bus setup and device setup
Currently, our PCI code uses the pcibios_fixup_bus() callback, which is called by the generic code when probing PCI buses, for two different things. One is to set up things related to the bus itself, such as reading bridge resources for P2P bridges, fixing them up, or setting up the iommu's associated with bridges on some platforms. The other is some setup for each individual device under that bridge, mostly setting up DMA mappings and interrupts. The problem is that this approach doesn't work well with PCI hotplug when an existing bus is re-probed for new children. We fix this problem by splitting pcibios_fixup_bus into two routines: pcibios_setup_bus_self() is now called to setup the bus itself pcibios_setup_bus_devices() is now called to setup devices pcibios_fixup_bus() is then modified to call these two after reading the bridge bases, and the OF based PCI probe is modified to avoid calling into the first one when rescanning an existing bridge. [paulus@samba.org - fixed eeh.h for 32-bit compile now that pci-common.c is including it unconditionally.] Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/eeh.h8
-rw-r--r--arch/powerpc/include/asm/pci.h5
-rw-r--r--arch/powerpc/kernel/pci-common.c54
-rw-r--r--arch/powerpc/kernel/pci_64.c27
4 files changed, 58 insertions, 36 deletions
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index b886bec67016..66ea9b8b95c5 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -17,8 +17,8 @@
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */ 18 */
19 19
20#ifndef _PPC64_EEH_H 20#ifndef _POWERPC_EEH_H
21#define _PPC64_EEH_H 21#define _POWERPC_EEH_H
22#ifdef __KERNEL__ 22#ifdef __KERNEL__
23 23
24#include <linux/init.h> 24#include <linux/init.h>
@@ -110,6 +110,7 @@ static inline void eeh_remove_bus_device(struct pci_dev *dev) { }
110#define EEH_IO_ERROR_VALUE(size) (-1UL) 110#define EEH_IO_ERROR_VALUE(size) (-1UL)
111#endif /* CONFIG_EEH */ 111#endif /* CONFIG_EEH */
112 112
113#ifdef CONFIG_PPC64
113/* 114/*
114 * MMIO read/write operations with EEH support. 115 * MMIO read/write operations with EEH support.
115 */ 116 */
@@ -207,5 +208,6 @@ static inline void eeh_readsl(const volatile void __iomem *addr, void * buf,
207 eeh_check_failure(addr, *(u32*)buf); 208 eeh_check_failure(addr, *(u32*)buf);
208} 209}
209 210
211#endif /* CONFIG_PPC64 */
210#endif /* __KERNEL__ */ 212#endif /* __KERNEL__ */
211#endif /* _PPC64_EEH_H */ 213#endif /* _POWERPC_EEH_H */
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 55542ac3eadb..32e03e6d25c5 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -221,6 +221,7 @@ extern void of_scan_pci_bridge(struct device_node *node,
221 struct pci_dev *dev); 221 struct pci_dev *dev);
222 222
223extern void of_scan_bus(struct device_node *node, struct pci_bus *bus); 223extern void of_scan_bus(struct device_node *node, struct pci_bus *bus);
224extern void of_rescan_bus(struct device_node *node, struct pci_bus *bus);
224 225
225extern int pci_read_irq_line(struct pci_dev *dev); 226extern int pci_read_irq_line(struct pci_dev *dev);
226 227
@@ -235,8 +236,8 @@ extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
235 const struct resource *rsrc, 236 const struct resource *rsrc,
236 resource_size_t *start, resource_size_t *end); 237 resource_size_t *start, resource_size_t *end);
237 238
238extern void pcibios_fixup_of_probed_bus(struct pci_bus *bus); 239extern void pcibios_setup_bus_devices(struct pci_bus *bus);
239 240extern void pcibios_setup_bus_self(struct pci_bus *bus);
240 241
241#endif /* __KERNEL__ */ 242#endif /* __KERNEL__ */
242#endif /* __ASM_POWERPC_PCI_H */ 243#endif /* __ASM_POWERPC_PCI_H */
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 780db386c1f0..0eaabd41474f 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -37,6 +37,7 @@
37#include <asm/machdep.h> 37#include <asm/machdep.h>
38#include <asm/ppc-pci.h> 38#include <asm/ppc-pci.h>
39#include <asm/firmware.h> 39#include <asm/firmware.h>
40#include <asm/eeh.h>
40 41
41static DEFINE_SPINLOCK(hose_spinlock); 42static DEFINE_SPINLOCK(hose_spinlock);
42 43
@@ -1074,31 +1075,17 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
1074 } 1075 }
1075} 1076}
1076 1077
1077static void __devinit __pcibios_fixup_bus(struct pci_bus *bus) 1078void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
1078{ 1079{
1079 struct pci_dev *dev; 1080 struct pci_dev *dev;
1080 1081
1081 pr_debug("PCI: Fixup bus %d (%s)\n", 1082 pr_debug("PCI: Fixup bus %d (%s)\n",
1082 bus->number, bus->self ? pci_name(bus->self) : "PHB"); 1083 bus->number, bus->self ? pci_name(bus->self) : "PHB");
1083 1084
1084 /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
1085 * now differently between 32 and 64 bits.
1086 */
1087 if (bus->self != NULL)
1088 pcibios_fixup_bridge(bus);
1089
1090 /* Setup bus DMA mappings */
1091 if (ppc_md.pci_dma_bus_setup)
1092 ppc_md.pci_dma_bus_setup(bus);
1093
1094 /* Setup DMA for all PCI devices on that bus */ 1085 /* Setup DMA for all PCI devices on that bus */
1095 list_for_each_entry(dev, &bus->devices, bus_list) 1086 list_for_each_entry(dev, &bus->devices, bus_list)
1096 pcibios_setup_new_device(dev); 1087 pcibios_setup_new_device(dev);
1097 1088
1098 /* Platform specific bus fixups */
1099 if (ppc_md.pcibios_fixup_bus)
1100 ppc_md.pcibios_fixup_bus(bus);
1101
1102 /* Read default IRQs and fixup if necessary */ 1089 /* Read default IRQs and fixup if necessary */
1103 list_for_each_entry(dev, &bus->devices, bus_list) { 1090 list_for_each_entry(dev, &bus->devices, bus_list) {
1104 pci_read_irq_line(dev); 1091 pci_read_irq_line(dev);
@@ -1107,25 +1094,39 @@ static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
1107 } 1094 }
1108} 1095}
1109 1096
1097void __devinit pcibios_setup_bus_self(struct pci_bus *bus)
1098{
1099 /* Fix up the bus resources */
1100 if (bus->self != NULL)
1101 pcibios_fixup_bridge(bus);
1102
1103 /* Platform specific bus fixups. This is currently only used
1104 * by fsl_pci and I'm hoping getting rid of it at some point
1105 */
1106 if (ppc_md.pcibios_fixup_bus)
1107 ppc_md.pcibios_fixup_bus(bus);
1108
1109 /* Setup bus DMA mappings */
1110 if (ppc_md.pci_dma_bus_setup)
1111 ppc_md.pci_dma_bus_setup(bus);
1112}
1113
1110void __devinit pcibios_fixup_bus(struct pci_bus *bus) 1114void __devinit pcibios_fixup_bus(struct pci_bus *bus)
1111{ 1115{
1112 /* When called from the generic PCI probe, read PCI<->PCI bridge 1116 /* When called from the generic PCI probe, read PCI<->PCI bridge
1113 * bases before proceeding 1117 * bases. This isn't called when generating the PCI tree from
1118 * the OF device-tree.
1114 */ 1119 */
1115 if (bus->self != NULL) 1120 if (bus->self != NULL)
1116 pci_read_bridge_bases(bus); 1121 pci_read_bridge_bases(bus);
1117 __pcibios_fixup_bus(bus);
1118}
1119EXPORT_SYMBOL(pcibios_fixup_bus);
1120 1122
1121/* When building a bus from the OF tree rather than probing, we need a 1123 /* Now fixup the bus bus */
1122 * slightly different version of the fixup which doesn't read the 1124 pcibios_setup_bus_self(bus);
1123 * bridge bases using config space accesses 1125
1124 */ 1126 /* Now fixup devices on that bus */
1125void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus) 1127 pcibios_setup_bus_devices(bus);
1126{
1127 __pcibios_fixup_bus(bus);
1128} 1128}
1129EXPORT_SYMBOL(pcibios_fixup_bus);
1129 1130
1130static int skip_isa_ioresource_align(struct pci_dev *dev) 1131static int skip_isa_ioresource_align(struct pci_dev *dev)
1131{ 1132{
@@ -1392,6 +1393,7 @@ void __init pcibios_resource_survey(void)
1392} 1393}
1393 1394
1394#ifdef CONFIG_HOTPLUG 1395#ifdef CONFIG_HOTPLUG
1396
1395/* This is used by the pSeries hotplug driver to allocate resource 1397/* This is used by the pSeries hotplug driver to allocate resource
1396 * of newly plugged busses. We can try to consolidate with the 1398 * of newly plugged busses. We can try to consolidate with the
1397 * rest of the code later, for now, keep it as-is 1399 * rest of the code later, for now, keep it as-is
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index e6e8813c364a..39fadc6e1492 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -189,8 +189,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
189} 189}
190EXPORT_SYMBOL(of_create_pci_dev); 190EXPORT_SYMBOL(of_create_pci_dev);
191 191
192void __devinit of_scan_bus(struct device_node *node, 192static void __devinit __of_scan_bus(struct device_node *node,
193 struct pci_bus *bus) 193 struct pci_bus *bus, int rescan_existing)
194{ 194{
195 struct device_node *child; 195 struct device_node *child;
196 const u32 *reg; 196 const u32 *reg;
@@ -215,8 +215,12 @@ void __devinit of_scan_bus(struct device_node *node,
215 pr_debug(" dev header type: %x\n", dev->hdr_type); 215 pr_debug(" dev header type: %x\n", dev->hdr_type);
216 } 216 }
217 217
218 /* Ally all fixups */ 218 /* Apply all fixups necessary. We don't fixup the bus "self"
219 pcibios_fixup_of_probed_bus(bus); 219 * for an existing bridge that is being rescanned
220 */
221 if (!rescan_existing)
222 pcibios_setup_bus_self(bus);
223 pcibios_setup_bus_devices(bus);
220 224
221 /* Now scan child busses */ 225 /* Now scan child busses */
222 list_for_each_entry(dev, &bus->devices, bus_list) { 226 list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -228,7 +232,20 @@ void __devinit of_scan_bus(struct device_node *node,
228 } 232 }
229 } 233 }
230} 234}
231EXPORT_SYMBOL(of_scan_bus); 235
236void __devinit of_scan_bus(struct device_node *node,
237 struct pci_bus *bus)
238{
239 __of_scan_bus(node, bus, 0);
240}
241EXPORT_SYMBOL_GPL(of_scan_bus);
242
243void __devinit of_rescan_bus(struct device_node *node,
244 struct pci_bus *bus)
245{
246 __of_scan_bus(node, bus, 1);
247}
248EXPORT_SYMBOL_GPL(of_rescan_bus);
232 249
233void __devinit of_scan_pci_bridge(struct device_node *node, 250void __devinit of_scan_pci_bridge(struct device_node *node,
234 struct pci_dev *dev) 251 struct pci_dev *dev)