Merge branch 'of-pci' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
Linus Torvalds [Fri, 22 Jul 2011 21:54:02 +0000 (14:54 -0700)]
* 'of-pci' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
  pci/of: Consolidate pci_bus_to_OF_node()
  pci/of: Consolidate pci_device_to_OF_node()
  x86/devicetree: Use generic PCI <-> OF matching
  microblaze/pci: Move the remains of pci_32.c to pci-common.c
  microblaze/pci: Remove powermac originated cruft
  pci/of: Match PCI devices to OF nodes dynamically

30 files changed:
arch/microblaze/include/asm/pci-bridge.h
arch/microblaze/include/asm/pci.h
arch/microblaze/include/asm/prom.h
arch/microblaze/pci/Makefile
arch/microblaze/pci/pci-common.c
arch/microblaze/pci/pci_32.c [deleted file]
arch/powerpc/include/asm/pci-bridge.h
arch/powerpc/include/asm/pci.h
arch/powerpc/include/asm/prom.h
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_dn.c
arch/powerpc/kernel/pci_of_scan.c
arch/powerpc/platforms/powermac/pci.c
arch/sparc/include/asm/pci_32.h
arch/sparc/include/asm/pci_64.h
arch/sparc/kernel/pci.c
arch/sparc/kernel/pcic.c
arch/x86/include/asm/prom.h
arch/x86/kernel/devicetree.c
drivers/of/Kconfig
drivers/of/Makefile
drivers/of/of_pci.c
drivers/of/of_pci_irq.c [new file with mode: 0644]
drivers/pci/Makefile
drivers/pci/hotplug/rpadlpar_core.c
drivers/pci/of.c [new file with mode: 0644]
drivers/pci/probe.c
include/linux/of_pci.h
include/linux/pci.h

index 746df91..242be57 100644 (file)
@@ -19,9 +19,6 @@ enum {
         */
        PCI_REASSIGN_ALL_RSRC   = 0x00000001,
 
-       /* Re-assign all bus numbers */
-       PCI_REASSIGN_ALL_BUS    = 0x00000002,
-
        /* Do not try to assign, just use existing setup */
        PCI_PROBE_ONLY          = 0x00000004,
 
@@ -110,16 +107,6 @@ static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
        return bus->sysdata;
 }
 
-static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
-{
-       struct pci_controller *host;
-
-       if (bus->self)
-               return pci_device_to_OF_node(bus->self);
-       host = pci_bus_to_host(bus);
-       return host ? host->dn : NULL;
-}
-
 static inline int isa_vaddr_is_ioport(void __iomem *address)
 {
        /* No specific ISA handling on ppc32 at this stage, it
index ba65cf4..1dd9d6b 100644 (file)
@@ -40,8 +40,7 @@ struct pci_dev;
  * Set this to 1 if you want the kernel to re-assign all PCI
  * bus numbers (don't do that on ppc64 yet !)
  */
-#define pcibios_assign_all_busses() \
-       (pci_has_flag(PCI_REASSIGN_ALL_BUS))
+#define pcibios_assign_all_busses()    0
 
 static inline void pcibios_set_master(struct pci_dev *dev)
 {
index d0890d3..9bd01ec 100644 (file)
 extern int early_uartlite_console(void);
 extern int early_uart16550_console(void);
 
-#ifdef CONFIG_PCI
-/*
- * PCI <-> OF matching functions
- * (XXX should these be here?)
- */
-struct pci_bus;
-struct pci_dev;
-extern int pci_device_from_OF_node(struct device_node *node,
-                                       u8 *bus, u8 *devfn);
-extern struct device_node *pci_busdev_to_OF_node(struct pci_bus *bus,
-                                                       int devfn);
-extern struct device_node *pci_device_to_OF_node(struct pci_dev *dev);
-extern void pci_create_OF_bus_map(void);
-#endif
-
 /*
  * OF address retreival & translation
  */
index 9889cc2..d1114fb 100644 (file)
@@ -2,5 +2,5 @@
 # Makefile
 #
 
-obj-$(CONFIG_PCI)              += pci_32.o pci-common.o indirect_pci.o iomap.o
+obj-$(CONFIG_PCI)              += pci-common.o indirect_pci.o iomap.o
 obj-$(CONFIG_PCI_XILINX)       += xilinx_pci.o
index 5359906..041b1d8 100644 (file)
@@ -50,6 +50,11 @@ unsigned int pci_flags;
 
 static struct dma_map_ops *pci_dma_ops = &dma_direct_ops;
 
+unsigned long isa_io_base;
+unsigned long pci_dram_offset;
+static int pci_bus_count;
+
+
 void set_pci_dma_ops(struct dma_map_ops *dma_ops)
 {
        pci_dma_ops = dma_ops;
@@ -1558,6 +1563,112 @@ void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
                 (unsigned long)hose->io_base_virt - _IO_BASE);
 }
 
+struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
+{
+       struct pci_controller *hose = bus->sysdata;
+
+       return of_node_get(hose->dn);
+}
+
+static void __devinit pcibios_scan_phb(struct pci_controller *hose)
+{
+       struct pci_bus *bus;
+       struct device_node *node = hose->dn;
+       unsigned long io_offset;
+       struct resource *res = &hose->io_resource;
+
+       pr_debug("PCI: Scanning PHB %s\n",
+                node ? node->full_name : "<NO NAME>");
+
+       /* Create an empty bus for the toplevel */
+       bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
+       if (bus == NULL) {
+               printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
+                      hose->global_number);
+               return;
+       }
+       bus->secondary = hose->first_busno;
+       hose->bus = bus;
+
+       /* Fixup IO space offset */
+       io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
+       res->start = (res->start + io_offset) & 0xffffffffu;
+       res->end = (res->end + io_offset) & 0xffffffffu;
+
+       /* Wire up PHB bus resources */
+       pcibios_setup_phb_resources(hose);
+
+       /* Scan children */
+       hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+}
+
+static int __init pcibios_init(void)
+{
+       struct pci_controller *hose, *tmp;
+       int next_busno = 0;
+
+       printk(KERN_INFO "PCI: Probing PCI hardware\n");
+
+       /* Scan all of the recorded PCI controllers.  */
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+               hose->last_busno = 0xff;
+               pcibios_scan_phb(hose);
+               printk(KERN_INFO "calling pci_bus_add_devices()\n");
+               pci_bus_add_devices(hose->bus);
+               if (next_busno <= hose->last_busno)
+                       next_busno = hose->last_busno + 1;
+       }
+       pci_bus_count = next_busno;
+
+       /* Call common code to handle resource allocation */
+       pcibios_resource_survey();
+
+       return 0;
+}
+
+subsys_initcall(pcibios_init);
+
+static struct pci_controller *pci_bus_to_hose(int bus)
+{
+       struct pci_controller *hose, *tmp;
+
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+               if (bus >= hose->first_busno && bus <= hose->last_busno)
+                       return hose;
+       return NULL;
+}
+
+/* Provide information on locations of various I/O regions in physical
+ * memory.  Do this on a per-card basis so that we choose the right
+ * root bridge.
+ * Note that the returned IO or memory base is a physical address
+ */
+
+long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
+{
+       struct pci_controller *hose;
+       long result = -EOPNOTSUPP;
+
+       hose = pci_bus_to_hose(bus);
+       if (!hose)
+               return -ENODEV;
+
+       switch (which) {
+       case IOBASE_BRIDGE_NUMBER:
+               return (long)hose->first_busno;
+       case IOBASE_MEMORY:
+               return (long)hose->pci_mem_offset;
+       case IOBASE_IO:
+               return (long)hose->io_base_phys;
+       case IOBASE_ISA_IO:
+               return (long)isa_io_base;
+       case IOBASE_ISA_MEM:
+               return (long)isa_mem_base;
+       }
+
+       return result;
+}
+
 /*
  * Null PCI config access functions, for the case when we can't
  * find a hose.
@@ -1626,3 +1737,4 @@ int early_find_capability(struct pci_controller *hose, int bus, int devfn,
 {
        return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);
 }
+
diff --git a/arch/microblaze/pci/pci_32.c b/arch/microblaze/pci/pci_32.c
deleted file mode 100644 (file)
index 92728a6..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Common pmac/prep/chrp pci routines. -- Cort
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/capability.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/bootmem.h>
-#include <linux/irq.h>
-#include <linux/list.h>
-#include <linux/of.h>
-#include <linux/slab.h>
-
-#include <asm/processor.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/sections.h>
-#include <asm/pci-bridge.h>
-#include <asm/byteorder.h>
-#include <asm/uaccess.h>
-
-#undef DEBUG
-
-unsigned long isa_io_base;
-unsigned long pci_dram_offset;
-int pcibios_assign_bus_offset = 1;
-
-static u8 *pci_to_OF_bus_map;
-
-/* By default, we don't re-assign bus numbers. We do this only on
- * some pmacs
- */
-static int pci_assign_all_buses;
-
-static int pci_bus_count;
-
-/*
- * Functions below are used on OpenFirmware machines.
- */
-static void
-make_one_node_map(struct device_node *node, u8 pci_bus)
-{
-       const int *bus_range;
-       int len;
-
-       if (pci_bus >= pci_bus_count)
-               return;
-       bus_range = of_get_property(node, "bus-range", &len);
-       if (bus_range == NULL || len < 2 * sizeof(int)) {
-               printk(KERN_WARNING "Can't get bus-range for %s, "
-                      "assuming it starts at 0\n", node->full_name);
-               pci_to_OF_bus_map[pci_bus] = 0;
-       } else
-               pci_to_OF_bus_map[pci_bus] = bus_range[0];
-
-       for_each_child_of_node(node, node) {
-               struct pci_dev *dev;
-               const unsigned int *class_code, *reg;
-
-               class_code = of_get_property(node, "class-code", NULL);
-               if (!class_code ||
-                       ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
-                       (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
-                       continue;
-               reg = of_get_property(node, "reg", NULL);
-               if (!reg)
-                       continue;
-               dev = pci_get_bus_and_slot(pci_bus, ((reg[0] >> 8) & 0xff));
-               if (!dev || !dev->subordinate) {
-                       pci_dev_put(dev);
-                       continue;
-               }
-               make_one_node_map(node, dev->subordinate->number);
-               pci_dev_put(dev);
-       }
-}
-
-void
-pcibios_make_OF_bus_map(void)
-{
-       int i;
-       struct pci_controller *hose, *tmp;
-       struct property *map_prop;
-       struct device_node *dn;
-
-       pci_to_OF_bus_map = kmalloc(pci_bus_count, GFP_KERNEL);
-       if (!pci_to_OF_bus_map) {
-               printk(KERN_ERR "Can't allocate OF bus map !\n");
-               return;
-       }
-
-       /* We fill the bus map with invalid values, that helps
-        * debugging.
-        */
-       for (i = 0; i < pci_bus_count; i++)
-               pci_to_OF_bus_map[i] = 0xff;
-
-       /* For each hose, we begin searching bridges */
-       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
-               struct device_node *node = hose->dn;
-
-               if (!node)
-                       continue;
-               make_one_node_map(node, hose->first_busno);
-       }
-       dn = of_find_node_by_path("/");
-       map_prop = of_find_property(dn, "pci-OF-bus-map", NULL);
-       if (map_prop) {
-               BUG_ON(pci_bus_count > map_prop->length);
-               memcpy(map_prop->value, pci_to_OF_bus_map, pci_bus_count);
-       }
-       of_node_put(dn);
-#ifdef DEBUG
-       printk(KERN_INFO "PCI->OF bus map:\n");
-       for (i = 0; i < pci_bus_count; i++) {
-               if (pci_to_OF_bus_map[i] == 0xff)
-                       continue;
-               printk(KERN_INFO "%d -> %d\n", i, pci_to_OF_bus_map[i]);
-       }
-#endif
-}
-
-typedef int (*pci_OF_scan_iterator)(struct device_node *node, void *data);
-
-static struct device_node *scan_OF_pci_childs(struct device_node *parent,
-                                       pci_OF_scan_iterator filter, void *data)
-{
-       struct device_node *node;
-       struct device_node *sub_node;
-
-       for_each_child_of_node(parent, node) {
-               const unsigned int *class_code;
-
-               if (filter(node, data)) {
-                       of_node_put(node);
-                       return node;
-               }
-
-               /* For PCI<->PCI bridges or CardBus bridges, we go down
-                * Note: some OFs create a parent node "multifunc-device" as
-                * a fake root for all functions of a multi-function device,
-                * we go down them as well.
-                */
-               class_code = of_get_property(node, "class-code", NULL);
-               if ((!class_code ||
-                       ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
-                       (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&
-                       strcmp(node->name, "multifunc-device"))
-                       continue;
-               sub_node = scan_OF_pci_childs(node, filter, data);
-               if (sub_node) {
-                       of_node_put(node);
-                       return sub_node;
-               }
-       }
-       return NULL;
-}
-
-static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
-                                              unsigned int devfn)
-{
-       struct device_node *np, *cnp;
-       const u32 *reg;
-       unsigned int psize;
-
-       for_each_child_of_node(parent, np) {
-               reg = of_get_property(np, "reg", &psize);
-               if (reg && psize >= 4 && ((reg[0] >> 8) & 0xff) == devfn)
-                       return np;
-
-               /* Note: some OFs create a parent node "multifunc-device" as
-                * a fake root for all functions of a multi-function device,
-                * we go down them as well. */
-               if (!strcmp(np->name, "multifunc-device")) {
-                       cnp = scan_OF_for_pci_dev(np, devfn);
-                       if (cnp)
-                               return cnp;
-               }
-       }
-       return NULL;
-}
-
-
-static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus)
-{
-       struct device_node *parent, *np;
-
-       /* Are we a root bus ? */
-       if (bus->self == NULL || bus->parent == NULL) {
-               struct pci_controller *hose = pci_bus_to_host(bus);
-               if (hose == NULL)
-                       return NULL;
-               return of_node_get(hose->dn);
-       }
-
-       /* not a root bus, we need to get our parent */
-       parent = scan_OF_for_pci_bus(bus->parent);
-       if (parent == NULL)
-               return NULL;
-
-       /* now iterate for children for a match */
-       np = scan_OF_for_pci_dev(parent, bus->self->devfn);
-       of_node_put(parent);
-
-       return np;
-}
-
-/*
- * Scans the OF tree for a device node matching a PCI device
- */
-struct device_node *
-pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
-{
-       struct device_node *parent, *np;
-
-       pr_debug("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn);
-       parent = scan_OF_for_pci_bus(bus);
-       if (parent == NULL)
-               return NULL;
-       pr_debug(" parent is %s\n", parent ? parent->full_name : "<NULL>");
-       np = scan_OF_for_pci_dev(parent, devfn);
-       of_node_put(parent);
-       pr_debug(" result is %s\n", np ? np->full_name : "<NULL>");
-
-       /* XXX most callers don't release the returned node
-        * mostly because ppc64 doesn't increase the refcount,
-        * we need to fix that.
-        */
-       return np;
-}
-EXPORT_SYMBOL(pci_busdev_to_OF_node);
-
-struct device_node*
-pci_device_to_OF_node(struct pci_dev *dev)
-{
-       return pci_busdev_to_OF_node(dev->bus, dev->devfn);
-}
-EXPORT_SYMBOL(pci_device_to_OF_node);
-
-static int
-find_OF_pci_device_filter(struct device_node *node, void *data)
-{
-       return ((void *)node == data);
-}
-
-/*
- * Returns the PCI device matching a given OF node
- */
-int
-pci_device_from_OF_node(struct device_node *node, u8 *bus, u8 *devfn)
-{
-       const unsigned int *reg;
-       struct pci_controller *hose;
-       struct pci_dev *dev = NULL;
-
-       /* Make sure it's really a PCI device */
-       hose = pci_find_hose_for_OF_device(node);
-       if (!hose || !hose->dn)
-               return -ENODEV;
-       if (!scan_OF_pci_childs(hose->dn,
-                       find_OF_pci_device_filter, (void *)node))
-               return -ENODEV;
-       reg = of_get_property(node, "reg", NULL);
-       if (!reg)
-               return -ENODEV;
-       *bus = (reg[0] >> 16) & 0xff;
-       *devfn = ((reg[0] >> 8) & 0xff);
-
-       /* Ok, here we need some tweak. If we have already renumbered
-        * all busses, we can't rely on the OF bus number any more.
-        * the pci_to_OF_bus_map is not enough as several PCI busses
-        * may match the same OF bus number.
-        */
-       if (!pci_to_OF_bus_map)
-               return 0;
-
-       for_each_pci_dev(dev)
-               if (pci_to_OF_bus_map[dev->bus->number] == *bus &&
-                               dev->devfn == *devfn) {
-                       *bus = dev->bus->number;
-                       pci_dev_put(dev);
-                       return 0;
-               }
-
-       return -ENODEV;
-}
-EXPORT_SYMBOL(pci_device_from_OF_node);
-
-/* We create the "pci-OF-bus-map" property now so it appears in the
- * /proc device tree
- */
-void __init
-pci_create_OF_bus_map(void)
-{
-       struct property *of_prop;
-       struct device_node *dn;
-
-       of_prop = (struct property *) alloc_bootmem(sizeof(struct property) + \
-                                                                        256);
-       if (!of_prop)
-               return;
-       dn = of_find_node_by_path("/");
-       if (dn) {
-               memset(of_prop, -1, sizeof(struct property) + 256);
-               of_prop->name = "pci-OF-bus-map";
-               of_prop->length = 256;
-               of_prop->value = &of_prop[1];
-               prom_add_property(dn, of_prop);
-               of_node_put(dn);
-       }
-}
-
-static void __devinit pcibios_scan_phb(struct pci_controller *hose)
-{
-       struct pci_bus *bus;
-       struct device_node *node = hose->dn;
-       unsigned long io_offset;
-       struct resource *res = &hose->io_resource;
-
-       pr_debug("PCI: Scanning PHB %s\n",
-                node ? node->full_name : "<NO NAME>");
-
-       /* Create an empty bus for the toplevel */
-       bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
-       if (bus == NULL) {
-               printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
-                      hose->global_number);
-               return;
-       }
-       bus.dev->of_node = of_node_get(node);
-       bus->secondary = hose->first_busno;
-       hose->bus = bus;
-
-       /* Fixup IO space offset */
-       io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
-       res->start = (res->start + io_offset) & 0xffffffffu;
-       res->end = (res->end + io_offset) & 0xffffffffu;
-
-       /* Wire up PHB bus resources */
-       pcibios_setup_phb_resources(hose);
-
-       /* Scan children */
-       hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
-}
-
-static int __init pcibios_init(void)
-{
-       struct pci_controller *hose, *tmp;
-       int next_busno = 0;
-
-       printk(KERN_INFO "PCI: Probing PCI hardware\n");
-
-       if (pci_flags & PCI_REASSIGN_ALL_BUS) {
-               printk(KERN_INFO "setting pci_asign_all_busses\n");
-               pci_assign_all_buses = 1;
-       }
-
-       /* Scan all of the recorded PCI controllers.  */
-       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
-               if (pci_assign_all_buses)
-                       hose->first_busno = next_busno;
-               hose->last_busno = 0xff;
-               pcibios_scan_phb(hose);
-               printk(KERN_INFO "calling pci_bus_add_devices()\n");
-               pci_bus_add_devices(hose->bus);
-               if (pci_assign_all_buses || next_busno <= hose->last_busno)
-                       next_busno = hose->last_busno + \
-                                       pcibios_assign_bus_offset;
-       }
-       pci_bus_count = next_busno;
-
-       /* OpenFirmware based machines need a map of OF bus
-        * numbers vs. kernel bus numbers since we may have to
-        * remap them.
-        */
-       if (pci_assign_all_buses)
-               pcibios_make_OF_bus_map();
-
-       /* Call common code to handle resource allocation */
-       pcibios_resource_survey();
-
-       return 0;
-}
-
-subsys_initcall(pcibios_init);
-
-static struct pci_controller*
-pci_bus_to_hose(int bus)
-{
-       struct pci_controller *hose, *tmp;
-
-       list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
-               if (bus >= hose->first_busno && bus <= hose->last_busno)
-                       return hose;
-       return NULL;
-}
-
-/* Provide information on locations of various I/O regions in physical
- * memory.  Do this on a per-card basis so that we choose the right
- * root bridge.
- * Note that the returned IO or memory base is a physical address
- */
-
-long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
-{
-       struct pci_controller *hose;
-       long result = -EOPNOTSUPP;
-
-       hose = pci_bus_to_hose(bus);
-       if (!hose)
-               return -ENODEV;
-
-       switch (which) {
-       case IOBASE_BRIDGE_NUMBER:
-               return (long)hose->first_busno;
-       case IOBASE_MEMORY:
-               return (long)hose->pci_mem_offset;
-       case IOBASE_IO:
-               return (long)hose->io_base_phys;
-       case IOBASE_ISA_IO:
-               return (long)isa_io_base;
-       case IOBASE_ISA_MEM:
-               return (long)isa_mem_base;
-       }
-
-       return result;
-}
index b90dbf8..90bd3ed 100644 (file)
@@ -171,15 +171,9 @@ static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
 
 #ifndef CONFIG_PPC64
 
-static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
-{
-       struct pci_controller *host;
-
-       if (bus->self)
-               return pci_device_to_OF_node(bus->self);
-       host = pci_bus_to_host(bus);
-       return host ? host->dn : NULL;
-}
+extern int pci_device_from_OF_node(struct device_node *node,
+                                  u8 *bus, u8 *devfn);
+extern void pci_create_OF_bus_map(void);
 
 static inline int isa_vaddr_is_ioport(void __iomem *address)
 {
@@ -223,17 +217,8 @@ struct pci_dn {
 /* Get the pointer to a device_node's pci_dn */
 #define PCI_DN(dn)     ((struct pci_dn *) (dn)->data)
 
-extern struct device_node *fetch_dev_dn(struct pci_dev *dev);
 extern void * update_dn_pci_info(struct device_node *dn, void *data);
 
-/* Get a device_node from a pci_dev.  This code must be fast except
- * in the case where the sysdata is incorrect and needs to be fixed
- * up (this will only happen once). */
-static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
-{
-       return dev->dev.of_node ? dev->dev.of_node : fetch_dev_dn(dev);
-}
-
 static inline int pci_device_from_OF_node(struct device_node *np,
                                          u8 *bus, u8 *devfn)
 {
@@ -244,14 +229,6 @@ static inline int pci_device_from_OF_node(struct device_node *np,
        return 0;
 }
 
-static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
-{
-       if (bus->self)
-               return pci_device_to_OF_node(bus->self);
-       else
-               return bus->dev.of_node; /* Must be root bus (PHB) */
-}
-
 /** Find the bus corresponding to the indicated device node */
 extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn);
 
index 7d77909..1f52268 100644 (file)
@@ -179,8 +179,7 @@ extern int remove_phb_dynamic(struct pci_controller *phb);
 extern struct pci_dev *of_create_pci_dev(struct device_node *node,
                                        struct pci_bus *bus, int devfn);
 
-extern void of_scan_pci_bridge(struct device_node *node,
-                               struct pci_dev *dev);
+extern void of_scan_pci_bridge(struct pci_dev *dev);
 
 extern void of_scan_bus(struct device_node *node, struct pci_bus *bus);
 extern void of_rescan_bus(struct device_node *node, struct pci_bus *bus);
index c189aa5..b823536 100644 (file)
 
 #define HAVE_ARCH_DEVTREE_FIXUPS
 
-#ifdef CONFIG_PPC32
-/*
- * PCI <-> OF matching functions
- * (XXX should these be here?)
- */
-struct pci_bus;
-struct pci_dev;
-extern int pci_device_from_OF_node(struct device_node *node,
-                                  u8* bus, u8* devfn);
-extern struct device_node* pci_busdev_to_OF_node(struct pci_bus *, int);
-extern struct device_node* pci_device_to_OF_node(struct pci_dev *);
-extern void pci_create_OF_bus_map(void);
-#endif
-
 /*
  * OF address retreival & translation
  */
index 893af2a..a3c9277 100644 (file)
@@ -1097,9 +1097,6 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
                if (dev->is_added)
                        continue;
 
-               /* Setup OF node pointer in the device */
-               dev->dev.of_node = pci_device_to_OF_node(dev);
-
                /* Fixup NUMA node as it may not be setup yet by the generic
                 * code and is needed by the DMA init
                 */
@@ -1685,6 +1682,13 @@ int early_find_capability(struct pci_controller *hose, int bus, int devfn,
        return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);
 }
 
+struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
+{
+       struct pci_controller *hose = bus->sysdata;
+
+       return of_node_get(hose->dn);
+}
+
 /**
  * pci_scan_phb - Given a pci_controller, setup and scan the PCI bus
  * @hose: Pointer to the PCI host controller instance structure
@@ -1705,7 +1709,6 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
                        hose->global_number);
                return;
        }
-       bus->dev.of_node = of_node_get(node);
        bus->secondary = hose->first_busno;
        hose->bus = bus;
 
index bedb370..8658550 100644 (file)
@@ -167,150 +167,26 @@ pcibios_make_OF_bus_map(void)
 #endif
 }
 
-typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data);
-
-static struct device_node*
-scan_OF_pci_childs(struct device_node *parent, pci_OF_scan_iterator filter, void* data)
-{
-       struct device_node *node;
-       struct device_node* sub_node;
-
-       for_each_child_of_node(parent, node) {
-               const unsigned int *class_code;
-       
-               if (filter(node, data)) {
-                       of_node_put(node);
-                       return node;
-               }
-
-               /* For PCI<->PCI bridges or CardBus bridges, we go down
-                * Note: some OFs create a parent node "multifunc-device" as
-                * a fake root for all functions of a multi-function device,
-                * we go down them as well.
-                */
-               class_code = of_get_property(node, "class-code", NULL);
-               if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
-                       (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&
-                       strcmp(node->name, "multifunc-device"))
-                       continue;
-               sub_node = scan_OF_pci_childs(node, filter, data);
-               if (sub_node) {
-                       of_node_put(node);
-                       return sub_node;
-               }
-       }
-       return NULL;
-}
-
-static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
-                                              unsigned int devfn)
-{
-       struct device_node *np, *cnp;
-       const u32 *reg;
-       unsigned int psize;
-
-       for_each_child_of_node(parent, np) {
-               reg = of_get_property(np, "reg", &psize);
-                if (reg && psize >= 4 && ((reg[0] >> 8) & 0xff) == devfn)
-                       return np;
-
-               /* Note: some OFs create a parent node "multifunc-device" as
-                * a fake root for all functions of a multi-function device,
-                * we go down them as well. */
-                if (!strcmp(np->name, "multifunc-device")) {
-                        cnp = scan_OF_for_pci_dev(np, devfn);
-                        if (cnp)
-                                return cnp;
-                }
-       }
-       return NULL;
-}
-
-
-static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus)
-{
-       struct device_node *parent, *np;
-
-       /* Are we a root bus ? */
-       if (bus->self == NULL || bus->parent == NULL) {
-               struct pci_controller *hose = pci_bus_to_host(bus);
-               if (hose == NULL)
-                       return NULL;
-               return of_node_get(hose->dn);
-       }
-
-       /* not a root bus, we need to get our parent */
-       parent = scan_OF_for_pci_bus(bus->parent);
-       if (parent == NULL)
-               return NULL;
-
-       /* now iterate for children for a match */
-       np = scan_OF_for_pci_dev(parent, bus->self->devfn);
-       of_node_put(parent);
-
-       return np;
-}
-
-/*
- * Scans the OF tree for a device node matching a PCI device
- */
-struct device_node *
-pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
-{
-       struct device_node *parent, *np;
-
-       pr_debug("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn);
-       parent = scan_OF_for_pci_bus(bus);
-       if (parent == NULL)
-               return NULL;
-       pr_debug(" parent is %s\n", parent ? parent->full_name : "<NULL>");
-       np = scan_OF_for_pci_dev(parent, devfn);
-       of_node_put(parent);
-       pr_debug(" result is %s\n", np ? np->full_name : "<NULL>");
-
-       /* XXX most callers don't release the returned node
-        * mostly because ppc64 doesn't increase the refcount,
-        * we need to fix that.
-        */
-       return np;
-}
-EXPORT_SYMBOL(pci_busdev_to_OF_node);
-
-struct device_node*
-pci_device_to_OF_node(struct pci_dev *dev)
-{
-       return pci_busdev_to_OF_node(dev->bus, dev->devfn);
-}
-EXPORT_SYMBOL(pci_device_to_OF_node);
-
-static int
-find_OF_pci_device_filter(struct device_node* node, void* data)
-{
-       return ((void *)node == data);
-}
 
 /*
  * Returns the PCI device matching a given OF node
  */
-int
-pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
+int pci_device_from_OF_node(struct device_node *node, u8 *bus, u8 *devfn)
 {
-       const unsigned int *reg;
-       struct pci_controller* hose;
-       struct pci_dev* dev = NULL;
-       
-       /* Make sure it's really a PCI device */
-       hose = pci_find_hose_for_OF_device(node);
-       if (!hose || !hose->dn)
-               return -ENODEV;
-       if (!scan_OF_pci_childs(hose->dn,
-                       find_OF_pci_device_filter, (void *)node))
+       struct pci_dev *dev = NULL;
+       const __be32 *reg;
+       int size;
+
+       /* Check if it might have a chance to be a PCI device */
+       if (!pci_find_hose_for_OF_device(node))
                return -ENODEV;
-       reg = of_get_property(node, "reg", NULL);
-       if (!reg)
+
+       reg = of_get_property(node, "reg", &size);
+       if (!reg || size < 5 * sizeof(u32))
                return -ENODEV;
-       *bus = (reg[0] >> 16) & 0xff;
-       *devfn = ((reg[0] >> 8) & 0xff);
+
+       *bus = (be32_to_cpup(&reg[0]) >> 16) & 0xff;
+       *devfn = (be32_to_cpup(&reg[0]) >> 8) & 0xff;
 
        /* Ok, here we need some tweak. If we have already renumbered
         * all busses, we can't rely on the OF bus number any more.
index 6baabc1..478f8d7 100644 (file)
@@ -142,53 +142,6 @@ void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb)
        traverse_pci_devices(dn, update_dn_pci_info, phb);
 }
 
-/*
- * Traversal func that looks for a <busno,devfcn> value.
- * If found, the pci_dn is returned (thus terminating the traversal).
- */
-static void *is_devfn_node(struct device_node *dn, void *data)
-{
-       int busno = ((unsigned long)data >> 8) & 0xff;
-       int devfn = ((unsigned long)data) & 0xff;
-       struct pci_dn *pci = dn->data;
-
-       if (pci && (devfn == pci->devfn) && (busno == pci->busno))
-               return dn;
-       return NULL;
-}
-
-/*
- * This is the "slow" path for looking up a device_node from a
- * pci_dev.  It will hunt for the device under its parent's
- * phb and then update of_node pointer.
- *
- * It may also do fixups on the actual device since this happens
- * on the first read/write.
- *
- * Note that it also must deal with devices that don't exist.
- * In this case it may probe for real hardware ("just in case")
- * and add a device_node to the device tree if necessary.
- *
- * Is this function necessary anymore now that dev->dev.of_node is
- * used to store the node pointer?
- *
- */
-struct device_node *fetch_dev_dn(struct pci_dev *dev)
-{
-       struct pci_controller *phb = dev->sysdata;
-       struct device_node *dn;
-       unsigned long searchval = (dev->bus->number << 8) | dev->devfn;
-
-       if (WARN_ON(!phb))
-               return NULL;
-
-       dn = traverse_pci_devices(phb->dn, is_devfn_node, (void *)searchval);
-       if (dn)
-               dev->dev.of_node = dn;
-       return dn;
-}
-EXPORT_SYMBOL(fetch_dev_dn);
-
 /** 
  * pci_devs_phb_init - Initialize phbs and pci devs under them.
  * 
index 1e89a72..fe0a5ad 100644 (file)
@@ -202,9 +202,9 @@ EXPORT_SYMBOL(of_create_pci_dev);
  * this routine in turn call of_scan_bus() recusively to scan for more child
  * devices.
  */
-void __devinit of_scan_pci_bridge(struct device_node *node,
-                                 struct pci_dev *dev)
+void __devinit of_scan_pci_bridge(struct pci_dev *dev)
 {
+       struct device_node *node = dev->dev.of_node;
        struct pci_bus *bus;
        const u32 *busrange, *ranges;
        int len, i, mode;
@@ -238,7 +238,6 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
        bus->primary = dev->bus->number;
        bus->subordinate = busrange[1];
        bus->bridge_ctl = 0;
-       bus->dev.of_node = of_node_get(node);
 
        /* parse ranges property */
        /* PCI #address-cells == 3 and #size-cells == 2 always */
@@ -335,9 +334,7 @@ static void __devinit __of_scan_bus(struct device_node *node,
        list_for_each_entry(dev, &bus->devices, bus_list) {
                if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
                    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
-                       struct device_node *child = pci_device_to_OF_node(dev);
-                       if (child)
-                               of_scan_pci_bridge(child, dev);
+                       of_scan_pci_bridge(dev);
                }
        }
 }
index f33e08d..abe8d7e 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/irq.h>
+#include <linux/of_pci.h>
 
 #include <asm/sections.h>
 #include <asm/io.h>
@@ -235,7 +236,7 @@ static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
 
        if (offset >= 0x100)
                return  PCIBIOS_BAD_REGISTER_NUMBER;
-       np = pci_busdev_to_OF_node(bus, devfn);
+       np = of_pci_find_child_device(bus->dev.of_node, devfn);
        if (np == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
index 862e3ce..02939ab 100644 (file)
@@ -42,9 +42,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 }
 #endif
 
-struct device_node;
-extern struct device_node *pci_device_to_OF_node(struct pci_dev *pdev);
-
 #endif /* __KERNEL__ */
 
 #ifndef CONFIG_LEON_PCI
index 948b686..2614d96 100644 (file)
@@ -91,9 +91,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
        return PCI_IRQ_NONE;
 }
 
-struct device_node;
-extern struct device_node *pci_device_to_OF_node(struct pci_dev *pdev);
-
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
 extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
                                 const struct resource *rsrc,
index 713dc91..80a87e2 100644 (file)
@@ -284,7 +284,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        dev->sysdata = node;
        dev->dev.parent = bus->bridge;
        dev->dev.bus = &pci_bus_type;
-       dev->dev.of_node = node;
+       dev->dev.of_node = of_node_get(node);
        dev->devfn = devfn;
        dev->multifunction = 0;         /* maybe a lie? */
        set_pcie_port_type(dev);
@@ -1021,12 +1021,6 @@ void arch_teardown_msi_irq(unsigned int irq)
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
-struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
-{
-       return pdev->dev.of_node;
-}
-EXPORT_SYMBOL(pci_device_to_OF_node);
-
 static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
 {
        struct pci_dev *ali_isa_bridge;
index 948601a..a19f041 100644 (file)
@@ -885,14 +885,6 @@ int pcibios_assign_resource(struct pci_dev *pdev, int resource)
        return -ENXIO;
 }
 
-struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
-{
-       struct pcidev_cookie *pc = pdev->sysdata;
-
-       return pc->prom_node;
-}
-EXPORT_SYMBOL(pci_device_to_OF_node);
-
 /*
  * This probably belongs here rather than ioport.c because
  * we do not want this crud linked into SBus kernels.
index 971e0b4..df12870 100644 (file)
@@ -30,17 +30,6 @@ extern void add_dtb(u64 data);
 extern void x86_add_irq_domains(void);
 void __cpuinit x86_of_pci_init(void);
 void x86_dtb_init(void);
-
-static inline struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
-{
-       return pdev ? pdev->dev.of_node : NULL;
-}
-
-static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
-{
-       return pci_device_to_OF_node(bus->self);
-}
-
 #else
 static inline void add_dtb(u64 data) { }
 static inline void x86_add_irq_domains(void) { }
index 9aeb78a..a621f34 100644 (file)
@@ -134,6 +134,24 @@ static int __init add_bus_probe(void)
 module_init(add_bus_probe);
 
 #ifdef CONFIG_PCI
+struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
+{
+       struct device_node *np;
+
+       for_each_node_by_type(np, "pci") {
+               const void *prop;
+               unsigned int bus_min;
+
+               prop = of_get_property(np, "bus-range", NULL);
+               if (!prop)
+                       continue;
+               bus_min = be32_to_cpup(prop);
+               if (bus->number == bus_min)
+                       return np;
+       }
+       return NULL;
+}
+
 static int x86_of_pci_irq_enable(struct pci_dev *dev)
 {
        struct of_irq oirq;
@@ -165,50 +183,8 @@ static void x86_of_pci_irq_disable(struct pci_dev *dev)
 
 void __cpuinit x86_of_pci_init(void)
 {
-       struct device_node *np;
-
        pcibios_enable_irq = x86_of_pci_irq_enable;
        pcibios_disable_irq = x86_of_pci_irq_disable;
-
-       for_each_node_by_type(np, "pci") {
-               const void *prop;
-               struct pci_bus *bus;
-               unsigned int bus_min;
-               struct device_node *child;
-
-               prop = of_get_property(np, "bus-range", NULL);
-               if (!prop)
-                       continue;
-               bus_min = be32_to_cpup(prop);
-
-               bus = pci_find_bus(0, bus_min);
-               if (!bus) {
-                       printk(KERN_ERR "Can't find a node for bus %s.\n",
-                                       np->full_name);
-                       continue;
-               }
-
-               if (bus->self)
-                       bus->self->dev.of_node = np;
-               else
-                       bus->dev.of_node = np;
-
-               for_each_child_of_node(np, child) {
-                       struct pci_dev *dev;
-                       u32 devfn;
-
-                       prop = of_get_property(child, "reg", NULL);
-                       if (!prop)
-                               continue;
-
-                       devfn = (be32_to_cpup(prop) >> 8) & 0xff;
-                       dev = pci_get_slot(bus, devfn);
-                       if (!dev)
-                               continue;
-                       dev->dev.of_node = child;
-                       pci_dev_put(dev);
-               }
-       }
 }
 #endif
 
index d06a637..cac63c9 100644 (file)
@@ -71,8 +71,14 @@ config OF_MDIO
 
 config OF_PCI
        def_tristate PCI
-       depends on PCI && (PPC || MICROBLAZE || X86)
+       depends on PCI
        help
          OpenFirmware PCI bus accessors
 
+config OF_PCI_IRQ
+       def_tristate PCI
+       depends on OF_PCI && OF_IRQ
+       help
+         OpenFirmware PCI IRQ routing helpers
+
 endmenu # OF
index f7861ed..dccb117 100644 (file)
@@ -10,3 +10,4 @@ obj-$(CONFIG_OF_NET)  += of_net.o
 obj-$(CONFIG_OF_SPI)   += of_spi.o
 obj-$(CONFIG_OF_MDIO)  += of_mdio.o
 obj-$(CONFIG_OF_PCI)   += of_pci.o
+obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
index ac1ec54..ec7b060 100644 (file)
@@ -1,92 +1,40 @@
 #include <linux/kernel.h>
 #include <linux/of_pci.h>
-#include <linux/of_irq.h>
 #include <asm/prom.h>
 
-/**
- * of_irq_map_pci - Resolve the interrupt for a PCI device
- * @pdev:       the device whose interrupt is to be resolved
- * @out_irq:    structure of_irq filled by this function
- *
- * This function resolves the PCI interrupt for a given PCI device. If a
- * device-node exists for a given pci_dev, it will use normal OF tree
- * walking. If not, it will implement standard swizzling and walk up the
- * PCI tree until an device-node is found, at which point it will finish
- * resolving using the OF tree walking.
- */
-int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
+static inline int __of_pci_pci_compare(struct device_node *node,
+                                      unsigned int devfn)
 {
-       struct device_node *dn, *ppnode;
-       struct pci_dev *ppdev;
-       u32 lspec;
-       __be32 lspec_be;
-       __be32 laddr[3];
-       u8 pin;
-       int rc;
+       unsigned int size;
+       const __be32 *reg = of_get_property(node, "reg", &size);
 
-       /* Check if we have a device node, if yes, fallback to standard
-        * device tree parsing
-        */
-       dn = pci_device_to_OF_node(pdev);
-       if (dn) {
-               rc = of_irq_map_one(dn, 0, out_irq);
-               if (!rc)
-                       return rc;
-       }
-
-       /* Ok, we don't, time to have fun. Let's start by building up an
-        * interrupt spec.  we assume #interrupt-cells is 1, which is standard
-        * for PCI. If you do different, then don't use that routine.
-        */
-       rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
-       if (rc != 0)
-               return rc;
-       /* No pin, exit */
-       if (pin == 0)
-               return -ENODEV;
-
-       /* Now we walk up the PCI tree */
-       lspec = pin;
-       for (;;) {
-               /* Get the pci_dev of our parent */
-               ppdev = pdev->bus->self;
-
-               /* Ouch, it's a host bridge... */
-               if (ppdev == NULL) {
-                       ppnode = pci_bus_to_OF_node(pdev->bus);
-
-                       /* No node for host bridge ? give up */
-                       if (ppnode == NULL)
-                               return -EINVAL;
-               } else {
-                       /* We found a P2P bridge, check if it has a node */
-                       ppnode = pci_device_to_OF_node(ppdev);
-               }
-
-               /* Ok, we have found a parent with a device-node, hand over to
-                * the OF parsing code.
-                * We build a unit address from the linux device to be used for
-                * resolution. Note that we use the linux bus number which may
-                * not match your firmware bus numbering.
-                * Fortunately, in most cases, interrupt-map-mask doesn't
-                * include the bus number as part of the matching.
-                * You should still be careful about that though if you intend
-                * to rely on this function (you ship  a firmware that doesn't
-                * create device nodes for all PCI devices).
-                */
-               if (ppnode)
-                       break;
+       if (!reg || size < 5 * sizeof(__be32))
+               return 0;
+       return ((be32_to_cpup(&reg[0]) >> 8) & 0xff) == devfn;
+}
 
-               /* We can only get here if we hit a P2P bridge with no node,
-                * let's do standard swizzling and try again
+struct device_node *of_pci_find_child_device(struct device_node *parent,
+                                            unsigned int devfn)
+{
+       struct device_node *node, *node2;
+
+       for_each_child_of_node(parent, node) {
+               if (__of_pci_pci_compare(node, devfn))
+                       return node;
+               /*
+                * Some OFs create a parent node "multifunc-device" as
+                * a fake root for all functions of a multi-function
+                * device we go down them as well.
                 */
-               lspec = pci_swizzle_interrupt_pin(pdev, lspec);
-               pdev = ppdev;
+               if (!strcmp(node->name, "multifunc-device")) {
+                       for_each_child_of_node(node, node2) {
+                               if (__of_pci_pci_compare(node2, devfn)) {
+                                       of_node_put(node);
+                                       return node2;
+                               }
+                       }
+               }
        }
-
-       lspec_be = cpu_to_be32(lspec);
-       laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8));
-       laddr[1]  = laddr[2] = cpu_to_be32(0);
-       return of_irq_map_raw(ppnode, &lspec_be, 1, laddr, out_irq);
+       return NULL;
 }
-EXPORT_SYMBOL_GPL(of_irq_map_pci);
+EXPORT_SYMBOL_GPL(of_pci_find_child_device);
diff --git a/drivers/of/of_pci_irq.c b/drivers/of/of_pci_irq.c
new file mode 100644 (file)
index 0000000..ac1ec54
--- /dev/null
@@ -0,0 +1,92 @@
+#include <linux/kernel.h>
+#include <linux/of_pci.h>
+#include <linux/of_irq.h>
+#include <asm/prom.h>
+
+/**
+ * of_irq_map_pci - Resolve the interrupt for a PCI device
+ * @pdev:       the device whose interrupt is to be resolved
+ * @out_irq:    structure of_irq filled by this function
+ *
+ * This function resolves the PCI interrupt for a given PCI device. If a
+ * device-node exists for a given pci_dev, it will use normal OF tree
+ * walking. If not, it will implement standard swizzling and walk up the
+ * PCI tree until an device-node is found, at which point it will finish
+ * resolving using the OF tree walking.
+ */
+int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
+{
+       struct device_node *dn, *ppnode;
+       struct pci_dev *ppdev;
+       u32 lspec;
+       __be32 lspec_be;
+       __be32 laddr[3];
+       u8 pin;
+       int rc;
+
+       /* Check if we have a device node, if yes, fallback to standard
+        * device tree parsing
+        */
+       dn = pci_device_to_OF_node(pdev);
+       if (dn) {
+               rc = of_irq_map_one(dn, 0, out_irq);
+               if (!rc)
+                       return rc;
+       }
+
+       /* Ok, we don't, time to have fun. Let's start by building up an
+        * interrupt spec.  we assume #interrupt-cells is 1, which is standard
+        * for PCI. If you do different, then don't use that routine.
+        */
+       rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
+       if (rc != 0)
+               return rc;
+       /* No pin, exit */
+       if (pin == 0)
+               return -ENODEV;
+
+       /* Now we walk up the PCI tree */
+       lspec = pin;
+       for (;;) {
+               /* Get the pci_dev of our parent */
+               ppdev = pdev->bus->self;
+
+               /* Ouch, it's a host bridge... */
+               if (ppdev == NULL) {
+                       ppnode = pci_bus_to_OF_node(pdev->bus);
+
+                       /* No node for host bridge ? give up */
+                       if (ppnode == NULL)
+                               return -EINVAL;
+               } else {
+                       /* We found a P2P bridge, check if it has a node */
+                       ppnode = pci_device_to_OF_node(ppdev);
+               }
+
+               /* Ok, we have found a parent with a device-node, hand over to
+                * the OF parsing code.
+                * We build a unit address from the linux device to be used for
+                * resolution. Note that we use the linux bus number which may
+                * not match your firmware bus numbering.
+                * Fortunately, in most cases, interrupt-map-mask doesn't
+                * include the bus number as part of the matching.
+                * You should still be careful about that though if you intend
+                * to rely on this function (you ship  a firmware that doesn't
+                * create device nodes for all PCI devices).
+                */
+               if (ppnode)
+                       break;
+
+               /* We can only get here if we hit a P2P bridge with no node,
+                * let's do standard swizzling and try again
+                */
+               lspec = pci_swizzle_interrupt_pin(pdev, lspec);
+               pdev = ppdev;
+       }
+
+       lspec_be = cpu_to_be32(lspec);
+       laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8));
+       laddr[1]  = laddr[2] = cpu_to_be32(0);
+       return of_irq_map_raw(ppnode, &lspec_be, 1, laddr, out_irq);
+}
+EXPORT_SYMBOL_GPL(of_irq_map_pci);
index 094308e..631f730 100644 (file)
@@ -71,4 +71,6 @@ obj-$(CONFIG_PCI_STUB) += pci-stub.o
 
 obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
 
+obj-$(CONFIG_OF) += of.o
+
 ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
index 0830347..1d002b1 100644 (file)
@@ -158,7 +158,7 @@ static void dlpar_pci_add_bus(struct device_node *dn)
        /* Scan below the new bridge */
        if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
            dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
-               of_scan_pci_bridge(dn, dev);
+               of_scan_pci_bridge(dev);
 
        /* Map IO space for child bus, which may or may not succeed */
        pcibios_map_io_space(dev->subordinate);
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
new file mode 100644 (file)
index 0000000..c94d37e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * PCI <-> OF mapping helpers
+ *
+ * Copyright 2011 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include "pci.h"
+
+void pci_set_of_node(struct pci_dev *dev)
+{
+       if (!dev->bus->dev.of_node)
+               return;
+       dev->dev.of_node = of_pci_find_child_device(dev->bus->dev.of_node,
+                                                   dev->devfn);
+}
+
+void pci_release_of_node(struct pci_dev *dev)
+{
+       of_node_put(dev->dev.of_node);
+       dev->dev.of_node = NULL;
+}
+
+void pci_set_bus_of_node(struct pci_bus *bus)
+{
+       if (bus->self == NULL)
+               bus->dev.of_node = pcibios_get_phb_of_node(bus);
+       else
+               bus->dev.of_node = of_node_get(bus->self->dev.of_node);
+}
+
+void pci_release_bus_of_node(struct pci_bus *bus)
+{
+       of_node_put(bus->dev.of_node);
+       bus->dev.of_node = NULL;
+}
+
+struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus)
+{
+       /* This should only be called for PHBs */
+       if (WARN_ON(bus->self || bus->parent))
+               return NULL;
+
+       /* Look for a node pointer in either the intermediary device we
+        * create above the root bus or it's own parent. Normally only
+        * the later is populated.
+        */
+       if (bus->bridge->of_node)
+               return of_node_get(bus->bridge->of_node);
+       if (bus->bridge->parent->of_node)
+               return of_node_get(bus->bridge->parent->of_node);
+       return NULL;
+}
index bafb3c3..9ab492f 100644 (file)
@@ -52,6 +52,7 @@ static void release_pcibus_dev(struct device *dev)
        if (pci_bus->bridge)
                put_device(pci_bus->bridge);
        pci_bus_remove_resources(pci_bus);
+       pci_release_bus_of_node(pci_bus);
        kfree(pci_bus);
 }
 
@@ -588,7 +589,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
 
        child->self = bridge;
        child->bridge = get_device(&bridge->dev);
-
+       pci_set_bus_of_node(child);
        pci_set_bus_speed(child);
 
        /* Set up default resource pointers and names.. */
@@ -1038,6 +1039,7 @@ static void pci_release_dev(struct device *dev)
 
        pci_dev = to_pci_dev(dev);
        pci_release_capabilities(pci_dev);
+       pci_release_of_node(pci_dev);
        kfree(pci_dev);
 }
 
@@ -1157,6 +1159,8 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
        dev->vendor = l & 0xffff;
        dev->device = (l >> 16) & 0xffff;
 
+       pci_set_of_node(dev);
+
        if (pci_setup_device(dev)) {
                kfree(dev);
                return NULL;
@@ -1409,6 +1413,7 @@ struct pci_bus * pci_create_bus(struct device *parent,
                goto dev_reg_err;
        b->bridge = get_device(dev);
        device_enable_async_suspend(b->bridge);
+       pci_set_bus_of_node(b);
 
        if (!parent)
                set_dev_node(b->bridge, pcibus_to_node(b));
index 85a27b6..f93e217 100644 (file)
@@ -6,4 +6,9 @@
 struct pci_dev;
 struct of_irq;
 int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
+
+struct device_node;
+struct device_node *of_pci_find_child_device(struct device_node *parent,
+                                            unsigned int devfn);
+
 #endif
index c446b5c..2d29218 100644 (file)
@@ -1589,5 +1589,33 @@ int pci_vpd_find_tag(const u8 *buf, unsigned int off, unsigned int len, u8 rdt);
 int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
                              unsigned int len, const char *kw);
 
+/* PCI <-> OF binding helpers */
+#ifdef CONFIG_OF
+struct device_node;
+extern void pci_set_of_node(struct pci_dev *dev);
+extern void pci_release_of_node(struct pci_dev *dev);
+extern void pci_set_bus_of_node(struct pci_bus *bus);
+extern void pci_release_bus_of_node(struct pci_bus *bus);
+
+/* Arch may override this (weak) */
+extern struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus);
+
+static inline struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
+{
+       return pdev ? pdev->dev.of_node : NULL;
+}
+
+static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
+{
+       return bus ? bus->dev.of_node : NULL;
+}
+
+#else /* CONFIG_OF */
+static inline void pci_set_of_node(struct pci_dev *dev) { }
+static inline void pci_release_of_node(struct pci_dev *dev) { }
+static inline void pci_set_bus_of_node(struct pci_bus *bus) { }
+static inline void pci_release_bus_of_node(struct pci_bus *bus) { }
+#endif  /* CONFIG_OF */
+
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */