/*
* 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
#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>
+#include <asm/atomic.h>
/*
* The list of OF IDs below is used for matching bus types in the
{ .type = "plb5", },
{ .type = "plb4", },
{ .type = "opb", },
+ { .type = "ebc", },
{},
};
+static atomic_t bus_no_reg_magic;
+
/*
*
* OF platform device type definition & base infrastructure
struct bus_type of_platform_bus_type = {
.name = "of_platform",
.match = of_platform_bus_match,
+ .uevent = of_device_uevent,
.probe = of_platform_device_probe,
.remove = of_platform_device_remove,
.suspend = of_platform_device_suspend,
char *name = dev->dev.bus_id;
const u32 *reg;
u64 addr;
+ int magic;
/*
* If it's a DCR based device, use 'd' for native DCRs
* and 'D' for MMIO DCRs.
*/
#ifdef CONFIG_PPC_DCR
- reg = get_property(node, "dcr-reg", NULL);
+ reg = of_get_property(node, "dcr-reg", NULL);
if (reg) {
#ifdef CONFIG_PPC_DCR_NATIVE
snprintf(name, BUS_ID_SIZE, "d%x.%s",
/*
* For MMIO, get the physical address
*/
- reg = get_property(node, "reg", NULL);
+ reg = of_get_property(node, "reg", NULL);
if (reg) {
addr = of_translate_address(node, reg);
if (addr != OF_BAD_ADDR) {
}
/*
- * No BusID, use the node name and pray
+ * No BusID, use the node name and add a globally incremented
+ * counter (and pray...)
*/
- snprintf(name, BUS_ID_SIZE, "%s", node->name);
+ magic = atomic_add_return(1, &bus_no_reg_magic);
+ snprintf(name, BUS_ID_SIZE, "%s.%d", node->name, magic - 1);
}
struct of_device* of_platform_device_create(struct device_node *np,
dev->dev.parent = parent;
dev->dev.bus = &of_platform_bus_type;
dev->dev.release = of_release_dev;
+ dev->dev.archdata.of_node = np;
+ dev->dev.archdata.numa_node = of_node_to_nid(np);
+
+ /* We do not fill the DMA ops for platform devices by default.
+ * This is currently the responsibility of the platform code
+ * to do such, possibly using a device notifier
+ */
if (bus_id)
strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
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);
+
+ /* 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,
+};
+
+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 */