aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-04-10 21:37:07 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-06-07 19:08:17 -0400
commit98d9f30c820d509145757e6ecbc36013aa02f7bc (patch)
treedd5da915d991352ced56ed849612029339f64198 /drivers/pci
parent1fa7b6a29c61358cc2ca6f64cef4aa0e1a7ca74c (diff)
pci/of: Match PCI devices to OF nodes dynamically
powerpc has two different ways of matching PCI devices to their corresponding OF node (if any) for historical reasons. The ppc64 one does a scan looking for matching bus/dev/fn, while the ppc32 one does a scan looking only for matching dev/fn on each level in order to be agnostic to busses being renumbered (which Linux does on some platforms). This removes both and instead moves the matching code to the PCI core itself. It's the most logical place to do it: when a pci_dev is created, we know the parent and thus can do a single level scan for the matching device_node (if any). The benefit is that all archs now get the matching for free. There's one hook the arch might want to provide to match a PHB bus to its device node. A default weak implementation is provided that looks for the parent device device node, but it's not entirely reliable on powerpc for various reasons so powerpc provides its own. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Acked-by: Michal Simek <monstr@monstr.eu> Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/hotplug/rpadlpar_core.c2
-rw-r--r--drivers/pci/of.c61
-rw-r--r--drivers/pci/probe.c7
4 files changed, 70 insertions, 2 deletions
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index c85f744270a5..f27f4a1488a1 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -70,4 +70,6 @@ obj-$(CONFIG_PCI_STUB) += pci-stub.o
70 70
71obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o 71obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
72 72
73obj-$(CONFIG_OF) += of.o
74
73ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG 75ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index 083034710fa6..1d002b1c2bf4 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -158,7 +158,7 @@ static void dlpar_pci_add_bus(struct device_node *dn)
158 /* Scan below the new bridge */ 158 /* Scan below the new bridge */
159 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || 159 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
160 dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) 160 dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
161 of_scan_pci_bridge(dn, dev); 161 of_scan_pci_bridge(dev);
162 162
163 /* Map IO space for child bus, which may or may not succeed */ 163 /* Map IO space for child bus, which may or may not succeed */
164 pcibios_map_io_space(dev->subordinate); 164 pcibios_map_io_space(dev->subordinate);
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
new file mode 100644
index 000000000000..c94d37ec55c8
--- /dev/null
+++ b/drivers/pci/of.c
@@ -0,0 +1,61 @@
1/*
2 * PCI <-> OF mapping helpers
3 *
4 * Copyright 2011 IBM Corp.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/kernel.h>
13#include <linux/pci.h>
14#include <linux/of.h>
15#include <linux/of_pci.h>
16#include "pci.h"
17
18void pci_set_of_node(struct pci_dev *dev)
19{
20 if (!dev->bus->dev.of_node)
21 return;
22 dev->dev.of_node = of_pci_find_child_device(dev->bus->dev.of_node,
23 dev->devfn);
24}
25
26void pci_release_of_node(struct pci_dev *dev)
27{
28 of_node_put(dev->dev.of_node);
29 dev->dev.of_node = NULL;
30}
31
32void pci_set_bus_of_node(struct pci_bus *bus)
33{
34 if (bus->self == NULL)
35 bus->dev.of_node = pcibios_get_phb_of_node(bus);
36 else
37 bus->dev.of_node = of_node_get(bus->self->dev.of_node);
38}
39
40void pci_release_bus_of_node(struct pci_bus *bus)
41{
42 of_node_put(bus->dev.of_node);
43 bus->dev.of_node = NULL;
44}
45
46struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus)
47{
48 /* This should only be called for PHBs */
49 if (WARN_ON(bus->self || bus->parent))
50 return NULL;
51
52 /* Look for a node pointer in either the intermediary device we
53 * create above the root bus or it's own parent. Normally only
54 * the later is populated.
55 */
56 if (bus->bridge->of_node)
57 return of_node_get(bus->bridge->of_node);
58 if (bus->bridge->parent->of_node)
59 return of_node_get(bus->bridge->parent->of_node);
60 return NULL;
61}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 48849ffdd672..c28c7b91910e 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -52,6 +52,7 @@ static void release_pcibus_dev(struct device *dev)
52 if (pci_bus->bridge) 52 if (pci_bus->bridge)
53 put_device(pci_bus->bridge); 53 put_device(pci_bus->bridge);
54 pci_bus_remove_resources(pci_bus); 54 pci_bus_remove_resources(pci_bus);
55 pci_release_bus_of_node(pci_bus);
55 kfree(pci_bus); 56 kfree(pci_bus);
56} 57}
57 58
@@ -588,7 +589,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
588 589
589 child->self = bridge; 590 child->self = bridge;
590 child->bridge = get_device(&bridge->dev); 591 child->bridge = get_device(&bridge->dev);
591 592 pci_set_bus_of_node(child);
592 pci_set_bus_speed(child); 593 pci_set_bus_speed(child);
593 594
594 /* Set up default resource pointers and names.. */ 595 /* Set up default resource pointers and names.. */
@@ -1038,6 +1039,7 @@ static void pci_release_dev(struct device *dev)
1038 1039
1039 pci_dev = to_pci_dev(dev); 1040 pci_dev = to_pci_dev(dev);
1040 pci_release_capabilities(pci_dev); 1041 pci_release_capabilities(pci_dev);
1042 pci_release_of_node(pci_dev);
1041 kfree(pci_dev); 1043 kfree(pci_dev);
1042} 1044}
1043 1045
@@ -1157,6 +1159,8 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
1157 dev->vendor = l & 0xffff; 1159 dev->vendor = l & 0xffff;
1158 dev->device = (l >> 16) & 0xffff; 1160 dev->device = (l >> 16) & 0xffff;
1159 1161
1162 pci_set_of_node(dev);
1163
1160 if (pci_setup_device(dev)) { 1164 if (pci_setup_device(dev)) {
1161 kfree(dev); 1165 kfree(dev);
1162 return NULL; 1166 return NULL;
@@ -1409,6 +1413,7 @@ struct pci_bus * pci_create_bus(struct device *parent,
1409 goto dev_reg_err; 1413 goto dev_reg_err;
1410 b->bridge = get_device(dev); 1414 b->bridge = get_device(dev);
1411 device_enable_async_suspend(b->bridge); 1415 device_enable_async_suspend(b->bridge);
1416 pci_set_bus_of_node(b);
1412 1417
1413 if (!parent) 1418 if (!parent)
1414 set_dev_node(b->bridge, pcibus_to_node(b)); 1419 set_dev_node(b->bridge, pcibus_to_node(b));