of/selftest: Use selftest() macro throughout
[linux-3.10.git] / drivers / of / of_pci.c
index ac1ec54..13e37e2 100644 (file)
@@ -1,92 +1,42 @@
 #include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/of.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);