|
@@ -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(®[0]) >> 16) & 0xff;
|
|
|
+ *devfn = (be32_to_cpup(®[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.
|