diff options
-rw-r--r-- | arch/powerpc/Kconfig | 6 | ||||
-rw-r--r-- | arch/powerpc/kernel/of_platform.c | 103 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci_64.c | 9 | ||||
-rw-r--r-- | arch/powerpc/kernel/rtas_pci.c | 7 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/setup.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pci_dlpar.c | 2 | ||||
-rw-r--r-- | include/asm-powerpc/machdep.h | 4 | ||||
-rw-r--r-- | include/asm-powerpc/ppc-pci.h | 12 |
8 files changed, 134 insertions, 10 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 65588a6bd2f..3d26ba7ad76 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -223,6 +223,11 @@ config PPC_DCR depends on PPC_DCR_NATIVE || PPC_DCR_MMIO default y +config PPC_OF_PLATFORM_PCI + bool + depends on PPC64 # not supported on 32 bits yet + default n + config BOOKE bool depends on E200 || E500 @@ -469,6 +474,7 @@ config PPC_CELL_NATIVE bool select PPC_CELL select PPC_DCR_MMIO + select PPC_OF_PLATFORM_PCI select MPIC default n diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index 7a0e77af7c9..6029543c1b5 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> + * and Arnd Bergmann, IBM Corp. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -17,12 +18,15 @@ #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/slab.h> +#include <linux/pci.h> #include <asm/errno.h> #include <asm/dcr.h> #include <asm/of_device.h> #include <asm/of_platform.h> #include <asm/topology.h> +#include <asm/pci-bridge.h> +#include <asm/ppc-pci.h> /* * The list of OF IDs below is used for matching bus types in the @@ -377,3 +381,102 @@ struct of_device *of_find_device_by_phandle(phandle ph) return NULL; } EXPORT_SYMBOL(of_find_device_by_phandle); + + +#ifdef CONFIG_PPC_OF_PLATFORM_PCI + +/* The probing of PCI controllers from of_platform is currently + * 64 bits only, mostly due to gratuitous differences between + * the 32 and 64 bits PCI code on PowerPC and the 32 bits one + * lacking some bits needed here. + */ + +static int __devinit of_pci_phb_probe(struct of_device *dev, + const struct of_device_id *match) +{ + struct pci_controller *phb; + + /* Check if we can do that ... */ + if (ppc_md.pci_setup_phb == NULL) + return -ENODEV; + + printk(KERN_INFO "Setting up PCI bus %s\n", dev->node->full_name); + + /* Alloc and setup PHB data structure */ + phb = pcibios_alloc_controller(dev->node); + if (!phb) + return -ENODEV; + + /* Setup parent in sysfs */ + phb->parent = &dev->dev; + + /* Setup the PHB using arch provided callback */ + if (ppc_md.pci_setup_phb(phb)) { + pcibios_free_controller(phb); + return -ENODEV; + } + + /* Process "ranges" property */ + pci_process_bridge_OF_ranges(phb, dev->node, 0); + + /* Setup IO space. + * This will not work properly for ISA IOs, something needs to be done + * about it if we ever generalize that way of probing PCI brigdes + */ + pci_setup_phb_io_dynamic(phb, 0); + + /* Init pci_dn data structures */ + pci_devs_phb_init_dynamic(phb); + + /* Register devices with EEH */ +#ifdef CONFIG_EEH + if (dev->node->child) + eeh_add_device_tree_early(dev->node); +#endif /* CONFIG_EEH */ + + /* Scan the bus */ + scan_phb(phb); + + /* Claim resources. This might need some rework as well depending + * wether we are doing probe-only or not, like assigning unassigned + * resources etc... + */ + pcibios_claim_one_bus(phb->bus); + + /* Finish EEH setup */ +#ifdef CONFIG_EEH + eeh_add_device_tree_late(phb->bus); +#endif + + /* Add probed PCI devices to the device model */ + pci_bus_add_devices(phb->bus); + + return 0; +} + +static struct of_device_id of_pci_phb_ids[] = { + { .type = "pci", }, + { .type = "pcix", }, + { .type = "pcie", }, + { .type = "pciex", }, + { .type = "ht", }, + {} +}; + +static struct of_platform_driver of_pci_phb_driver = { + .name = "of-pci", + .match_table = of_pci_phb_ids, + .probe = of_pci_phb_probe, + .driver = { + .multithread_probe = 1, + }, +}; + +static __init int of_pci_phb_init(void) +{ + return of_register_platform_driver(&of_pci_phb_driver); +} + +device_initcall(of_pci_phb_init); + +#endif /* CONFIG_PPC_OF_PLATFORM_PCI */ diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 74e580d25c1..d800e19ea56 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -210,6 +210,10 @@ struct pci_controller * pcibios_alloc_controller(struct device_node *dev) void pcibios_free_controller(struct pci_controller *phb) { + spin_lock(&hose_spinlock); + list_del(&phb->list_node); + spin_unlock(&hose_spinlock); + if (phb->is_dynamic) kfree(phb); } @@ -1242,6 +1246,11 @@ static void __devinit do_bus_setup(struct pci_bus *bus) void __devinit pcibios_fixup_bus(struct pci_bus *bus) { struct pci_dev *dev = bus->self; + struct device_node *np; + + np = pci_bus_to_OF_node(bus); + + DBG("pcibios_fixup_bus(%s)\n", np ? np->full_name : "<???>"); if (dev && pci_probe_only && (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 2576e12d725..03cacc25a0a 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c @@ -257,8 +257,10 @@ static int phb_set_bus_ranges(struct device_node *dev, return 0; } -int __devinit setup_phb(struct device_node *dev, struct pci_controller *phb) +int __devinit rtas_setup_phb(struct pci_controller *phb) { + struct device_node *dev = phb->arch_data; + if (is_python(dev)) python_countermeasures(dev); @@ -290,7 +292,7 @@ unsigned long __init find_and_init_phbs(void) phb = pcibios_alloc_controller(node); if (!phb) continue; - setup_phb(node, phb); + rtas_setup_phb(phb); pci_process_bridge_OF_ranges(phb, node, 0); pci_setup_phb_io(phb, index == 0); index++; @@ -362,7 +364,6 @@ int pcibios_remove_root_bus(struct pci_controller *phb) } } - list_del(&phb->list_node); pcibios_free_controller(phb); return 0; diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index b39753f16d4..7e18420166c 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -256,6 +256,7 @@ define_machine(cell) { .check_legacy_ioport = cell_check_legacy_ioport, .progress = cell_progress, .init_IRQ = cell_init_irq, + .pci_setup_phb = rtas_setup_phb, #ifdef CONFIG_KEXEC .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index bb0cb5c5b56..ac56b868913 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -195,7 +195,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) phb = pcibios_alloc_controller(dn); if (!phb) return NULL; - setup_phb(dn, phb); + rtas_setup_phb(phb); pci_process_bridge_OF_ranges(phb, dn, 0); pci_setup_phb_io_dynamic(phb, primary); diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index ccc29744656..23580cf5504 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -26,6 +26,7 @@ struct device_node; struct iommu_table; struct rtc_time; struct file; +struct pci_controller; #ifdef CONFIG_KEXEC struct kimage; #endif @@ -107,6 +108,9 @@ struct machdep_calls { int (*pci_probe_mode)(struct pci_bus *); void (*pci_irq_fixup)(struct pci_dev *dev); + /* To setup PHBs when using automatic OF platform driver for PCI */ + int (*pci_setup_phb)(struct pci_controller *host); + void (*restart)(char *cmd); void (*power_off)(void); void (*halt)(void); diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h index 8894d1d4226..ab6eddb518c 100644 --- a/include/asm-powerpc/ppc-pci.h +++ b/include/asm-powerpc/ppc-pci.h @@ -36,14 +36,14 @@ typedef void *(*traverse_func)(struct device_node *me, void *data); void *traverse_pci_devices(struct device_node *start, traverse_func pre, void *data); -void pci_devs_phb_init(void); -void pci_devs_phb_init_dynamic(struct pci_controller *phb); -int setup_phb(struct device_node *dev, struct pci_controller *phb); -void __devinit scan_phb(struct pci_controller *hose); +extern void pci_devs_phb_init(void); +extern void pci_devs_phb_init_dynamic(struct pci_controller *phb); +extern void scan_phb(struct pci_controller *hose); /* From rtas_pci.h */ -void init_pci_config_tokens (void); -unsigned long get_phb_buid (struct device_node *); +extern void init_pci_config_tokens (void); +extern unsigned long get_phb_buid (struct device_node *); +extern int rtas_setup_phb(struct pci_controller *phb); /* From pSeries_pci.h */ extern void pSeries_final_fixup(void); |