Here's a new batch. This time, I'm reasonably confident I build-tested the
right commit-id's on sparc :-)
To sort out the sparc problem I took a slightly different approach than
discussed. I made the new code be of_pci.c (which I enabled on sparc)
and put the old stuff into of_pci_irq.c (which should still be disabled
there).
I've also consolidated pci_bus_to_OF_node() while at it.
All archs do more or less the same thing now, move it into
a single generic place.
I chose pci.h rather than of_pci.h to avoid having to change
all call-sites to include the later.
Signed-off-by: Benjamin Herrenschmidt <[email protected]>
---
arch/microblaze/include/asm/pci-bridge.h | 5 -----
arch/powerpc/include/asm/pci-bridge.h | 5 -----
arch/sparc/include/asm/pci_32.h | 3 ---
arch/sparc/include/asm/pci_64.h | 3 ---
arch/sparc/kernel/pci.c | 6 ------
arch/sparc/kernel/pcic.c | 8 --------
arch/x86/include/asm/prom.h | 5 -----
include/linux/pci.h | 5 +++++
8 files changed, 5 insertions(+), 35 deletions(-)
diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
index 6bddc07..0d74d03 100644
--- a/arch/microblaze/include/asm/pci-bridge.h
+++ b/arch/microblaze/include/asm/pci-bridge.h
@@ -102,11 +102,6 @@ struct pci_controller {
};
#ifdef CONFIG_PCI
-static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
-{
- return dev->dev.of_node;
-}
-
static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
{
return bus->dev.of_node;
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 3e68694..578060e 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -169,11 +169,6 @@ static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
return bus->sysdata;
}
-static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
-{
- return dev->dev.of_node;
-}
-
static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
{
return bus->dev.of_node;
diff --git a/arch/sparc/include/asm/pci_32.h b/arch/sparc/include/asm/pci_32.h
index 332ac9a..4d0c39a 100644
--- a/arch/sparc/include/asm/pci_32.h
+++ b/arch/sparc/include/asm/pci_32.h
@@ -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__ */
/* generic pci stuff */
diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index 948b686..2614d96 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -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,
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index e539d23..80a87e2 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -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;
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 2cdc131..7558b6e 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -856,14 +856,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.
diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h
index 971e0b4..dd6066a 100644
--- a/arch/x86/include/asm/prom.h
+++ b/arch/x86/include/asm/prom.h
@@ -31,11 +31,6 @@ 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);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index f2a25f8..73dab8a 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1554,6 +1554,11 @@ 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;
+}
+
#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) { }
--
1.7.1
The whole business with re-assigning all bus numbers, creating
an OF bus "map" etc... is ancient powermac stuff that you really
don't care about on microblaze.
Similarly pci_device_from_OF_node() is unused and by getting rid
of it we can get rid of a whole lot of code otherwise unused on
this architecture
Signed-off-by: Benjamin Herrenschmidt <[email protected]>
---
arch/microblaze/include/asm/pci-bridge.h | 3 -
arch/microblaze/include/asm/pci.h | 3 +-
arch/microblaze/pci/pci_32.c | 272 +-----------------------------
3 files changed, 3 insertions(+), 275 deletions(-)
diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
index 728f8d6..6bddc07 100644
--- a/arch/microblaze/include/asm/pci-bridge.h
+++ b/arch/microblaze/include/asm/pci-bridge.h
@@ -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,
diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index ba65cf4..1dd9d6b 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -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)
{
diff --git a/arch/microblaze/pci/pci_32.c b/arch/microblaze/pci/pci_32.c
index 2fa9506..ab3c4d4 100644
--- a/arch/microblaze/pci/pci_32.c
+++ b/arch/microblaze/pci/pci_32.c
@@ -28,261 +28,8 @@
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;
-}
-
-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);
- }
-}
-
struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
{
struct pci_controller *hose = bus->sysdata;
@@ -329,32 +76,17 @@ static int __init pcibios_init(void)
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;
+ if (next_busno <= hose->last_busno)
+ next_busno = hose->last_busno + 1;
}
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();
--
1.7.1
There's no point in keeping this separate. Even if microblaze grows
a 64-bit variant, it will probably be able to re-use that code as-is
Signed-off-by: Benjamin Herrenschmidt <[email protected]>
---
arch/microblaze/pci/Makefile | 2 +-
arch/microblaze/pci/pci-common.c | 112 ++++++++++++++++++++++++++++++
arch/microblaze/pci/pci_32.c | 138 --------------------------------------
3 files changed, 113 insertions(+), 139 deletions(-)
delete mode 100644 arch/microblaze/pci/pci_32.c
diff --git a/arch/microblaze/pci/Makefile b/arch/microblaze/pci/Makefile
index 9889cc2..d1114fb 100644
--- a/arch/microblaze/pci/Makefile
+++ b/arch/microblaze/pci/Makefile
@@ -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
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 5359906..041b1d8 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -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
index ab3c4d4..0000000
--- a/arch/microblaze/pci/pci_32.c
+++ /dev/null
@@ -1,138 +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;
-static int pci_bus_count;
-
-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;
-}
--
1.7.1
The generic code always get the device-node in the right place now
so a single implementation will work for all archs
Signed-off-by: Benjamin Herrenschmidt <[email protected]>
---
arch/microblaze/include/asm/pci-bridge.h | 5 -----
arch/powerpc/include/asm/pci-bridge.h | 5 -----
arch/x86/include/asm/prom.h | 6 ------
include/linux/pci.h | 5 +++++
4 files changed, 5 insertions(+), 16 deletions(-)
diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
index 0d74d03..242be57 100644
--- a/arch/microblaze/include/asm/pci-bridge.h
+++ b/arch/microblaze/include/asm/pci-bridge.h
@@ -102,11 +102,6 @@ struct pci_controller {
};
#ifdef CONFIG_PCI
-static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
-{
- return bus->dev.of_node;
-}
-
static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
{
return bus->sysdata;
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 578060e..90bd3ed 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -169,11 +169,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)
-{
- return bus->dev.of_node;
-}
-
#ifndef CONFIG_PPC64
extern int pci_device_from_OF_node(struct device_node *node,
diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h
index dd6066a..df12870 100644
--- a/arch/x86/include/asm/prom.h
+++ b/arch/x86/include/asm/prom.h
@@ -30,12 +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_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) { }
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 73dab8a..532c4e8 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1559,6 +1559,11 @@ 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) { }
--
1.7.1
Instead of walking the whole PCI tree to update the of_node's for
PCI busses and devices after the fact, enable the new generic core
code for doing so by providing the proper device nodes for the
PCI host bridges
Signed-off-by: Benjamin Herrenschmidt <[email protected]>
---
arch/x86/kernel/devicetree.c | 60 +++++++++---------------------
arch/x86/platform/ce4100/falconfalls.dts | 2 +
2 files changed, 20 insertions(+), 42 deletions(-)
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index 706a9fb..3568496 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -123,6 +123,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;
@@ -154,50 +172,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
diff --git a/arch/x86/platform/ce4100/falconfalls.dts b/arch/x86/platform/ce4100/falconfalls.dts
index dc701ea..2d6d226 100644
--- a/arch/x86/platform/ce4100/falconfalls.dts
+++ b/arch/x86/platform/ce4100/falconfalls.dts
@@ -74,6 +74,7 @@
compatible = "intel,ce4100-pci", "pci";
device_type = "pci";
bus-range = <1 1>;
+ reg = <0x0800 0x0 0x0 0x0 0x0>;
ranges = <0x2000000 0 0xdffe0000 0x2000000 0 0xdffe0000 0 0x1000>;
interrupt-parent = <&ioapic2>;
@@ -412,6 +413,7 @@
#address-cells = <2>;
#size-cells = <1>;
compatible = "isa";
+ reg = <0xf800 0x0 0x0 0x0 0x0>;
ranges = <1 0 0 0 0 0x100>;
rtc@70 {
--
1.7.1
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 <[email protected]>
---
arch/microblaze/include/asm/pci-bridge.h | 14 ++--
arch/microblaze/include/asm/prom.h | 15 ---
arch/microblaze/pci/pci_32.c | 40 ++-------
arch/powerpc/include/asm/pci-bridge.h | 35 ++-----
arch/powerpc/include/asm/pci.h | 3 +-
arch/powerpc/include/asm/prom.h | 14 ---
arch/powerpc/kernel/pci-common.c | 11 ++-
arch/powerpc/kernel/pci_32.c | 150 +++---------------------------
arch/powerpc/kernel/pci_dn.c | 47 ---------
arch/powerpc/kernel/pci_of_scan.c | 9 +-
arch/powerpc/platforms/powermac/pci.c | 3 +-
arch/sparc/kernel/pci.c | 2 +-
drivers/of/Kconfig | 8 ++-
drivers/of/Makefile | 1 +
drivers/of/of_pci.c | 112 ++++++----------------
drivers/of/of_pci_irq.c | 92 ++++++++++++++++++
drivers/pci/Makefile | 2 +
drivers/pci/hotplug/rpadlpar_core.c | 2 +-
drivers/pci/of.c | 61 ++++++++++++
drivers/pci/probe.c | 7 +-
include/linux/of_pci.h | 5 +
include/linux/pci.h | 18 ++++
22 files changed, 275 insertions(+), 376 deletions(-)
create mode 100644 drivers/of/of_pci_irq.c
create mode 100644 drivers/pci/of.c
diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
index 746df91..728f8d6 100644
--- a/arch/microblaze/include/asm/pci-bridge.h
+++ b/arch/microblaze/include/asm/pci-bridge.h
@@ -105,19 +105,19 @@ struct pci_controller {
};
#ifdef CONFIG_PCI
-static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
+static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
{
- return bus->sysdata;
+ return dev->dev.of_node;
}
static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
{
- struct pci_controller *host;
+ return bus->dev.of_node;
+}
- if (bus->self)
- return pci_device_to_OF_node(bus->self);
- host = pci_bus_to_host(bus);
- return host ? host->dn : NULL;
+static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
+{
+ return bus->sysdata;
}
static inline int isa_vaddr_is_ioport(void __iomem *address)
diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
index d0890d3..9bd01ec 100644
--- a/arch/microblaze/include/asm/prom.h
+++ b/arch/microblaze/include/asm/prom.h
@@ -29,21 +29,6 @@
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
*/
diff --git a/arch/microblaze/pci/pci_32.c b/arch/microblaze/pci/pci_32.c
index 92728a6..2fa9506 100644
--- a/arch/microblaze/pci/pci_32.c
+++ b/arch/microblaze/pci/pci_32.c
@@ -210,38 +210,6 @@ static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus)
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)
{
@@ -315,6 +283,13 @@ pci_create_OF_bus_map(void)
}
}
+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;
@@ -332,7 +307,6 @@ static 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;
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index b90dbf8..3e68694 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -169,18 +169,22 @@ static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
return bus->sysdata;
}
-#ifndef CONFIG_PPC64
+static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
+{
+ return dev->dev.of_node;
+}
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;
+ return bus->dev.of_node;
}
+#ifndef CONFIG_PPC64
+
+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)
{
/* No specific ISA handling on ppc32 at this stage, it
@@ -223,17 +227,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 +239,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);
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 7d77909..1f52268 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -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);
diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
index c189aa5..b823536 100644
--- a/arch/powerpc/include/asm/prom.h
+++ b/arch/powerpc/include/asm/prom.h
@@ -22,20 +22,6 @@
#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
*/
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 893af2a..a3c9277 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -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;
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index bedb370..8658550 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -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.
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index d225d99..8cb66a2 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -143,53 +143,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.
*
diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
index 1e89a72..fe0a5ad 100644
--- a/arch/powerpc/kernel/pci_of_scan.c
+++ b/arch/powerpc/kernel/pci_of_scan.c
@@ -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);
}
}
}
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index f33e08d..abe8d7e 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -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;
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 713dc91..e539d23 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -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);
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index d06a637..cac63c9 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -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
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index f7861ed..dccb117 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -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
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index ac1ec54..ec7b060 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -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(®[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
index 0000000..ac1ec54
--- /dev/null
+++ b/drivers/of/of_pci_irq.c
@@ -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);
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 98d61c8..d5c3cb9 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -70,4 +70,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
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index 0830347..1d002b1 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)
/* 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
index 0000000..c94d37e
--- /dev/null
+++ b/drivers/pci/of.c
@@ -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;
+}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 44cbbba..7964474 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -89,6 +89,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);
}
@@ -624,7 +625,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.. */
@@ -1074,6 +1075,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);
}
@@ -1193,6 +1195,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;
@@ -1445,6 +1449,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));
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 85a27b6..f93e217 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -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
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 96f70d7..f2a25f8 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1543,5 +1543,23 @@ 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);
+
+#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 */
--
1.7.1
> There's no point in keeping this separate. Even if microblaze grows
> a 64-bit variant, it will probably be able to re-use that code as-is
> diff --git a/arch/microblaze/pci/pci-common.c
> b/arch/microblaze/pci/pci-common.c
> index 5359906..041b1d8 100644
> --- a/arch/microblaze/pci/pci-common.c
> +++ b/arch/microblaze/pci/pci-common.c
> @@ -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;
> +
> +
Extra newline.
Eike
On Mon, 2011-04-11 at 15:12 +0000, Rolf Eike Beer wrote:
> > There's no point in keeping this separate. Even if microblaze grows
> > a 64-bit variant, it will probably be able to re-use that code as-is
>
> > diff --git a/arch/microblaze/pci/pci-common.c
> > b/arch/microblaze/pci/pci-common.c
> > index 5359906..041b1d8 100644
> > --- a/arch/microblaze/pci/pci-common.c
> > +++ b/arch/microblaze/pci/pci-common.c
> > @@ -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;
> > +
> > +
>
> Extra newline.
Can people with no useful content abstain from commenting please.
Cheers,
Ben.
* Benjamin Herrenschmidt | 2011-04-11 14:12:44 [+1000]:
>Here's a new batch. This time, I'm reasonably confident I build-tested the
>right commit-id's on sparc :-)
>
>To sort out the sparc problem I took a slightly different approach than
>discussed. I made the new code be of_pci.c (which I enabled on sparc)
>and put the old stuff into of_pci_irq.c (which should still be disabled
>there).
>
>I've also consolidated pci_bus_to_OF_node() while at it.
This series builds and boots fine on x86.
Sebastian
On Sun, Apr 10, 2011 at 10:12 PM, Benjamin Herrenschmidt
<[email protected]> wrote:
> 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 <[email protected]>
Looks good to me. I've not tested this, but I think it is the right
approach. It makes me a little nervous because the patch is quite
large and seems to fix up several things at once (like the movement of
of_irq_map_pci(), and bug fixes like adding of_node_get() calls). I'm
not going to make a stink about it, but it is hard to review in this
form. Since this touches several architectures and also core pci
code, I think it is probably best (as you suggested on IRC) to put it
into a separate branch and get sfr to add it to linux-next. If
anything goes wrong, then sfr can punt it independently. :-)
You'll need to check with Jesse also.
Inadequately-reviewed-by:: Grant Likely <[email protected]>
g.
> ---
> ?arch/microblaze/include/asm/pci-bridge.h | ? 14 ++--
> ?arch/microblaze/include/asm/prom.h ? ? ? | ? 15 ---
> ?arch/microblaze/pci/pci_32.c ? ? ? ? ? ? | ? 40 ++-------
> ?arch/powerpc/include/asm/pci-bridge.h ? ?| ? 35 ++-----
> ?arch/powerpc/include/asm/pci.h ? ? ? ? ? | ? ?3 +-
> ?arch/powerpc/include/asm/prom.h ? ? ? ? ?| ? 14 ---
> ?arch/powerpc/kernel/pci-common.c ? ? ? ? | ? 11 ++-
> ?arch/powerpc/kernel/pci_32.c ? ? ? ? ? ? | ?150 +++---------------------------
> ?arch/powerpc/kernel/pci_dn.c ? ? ? ? ? ? | ? 47 ---------
> ?arch/powerpc/kernel/pci_of_scan.c ? ? ? ?| ? ?9 +-
> ?arch/powerpc/platforms/powermac/pci.c ? ?| ? ?3 +-
> ?arch/sparc/kernel/pci.c ? ? ? ? ? ? ? ? ?| ? ?2 +-
> ?drivers/of/Kconfig ? ? ? ? ? ? ? ? ? ? ? | ? ?8 ++-
> ?drivers/of/Makefile ? ? ? ? ? ? ? ? ? ? ?| ? ?1 +
> ?drivers/of/of_pci.c ? ? ? ? ? ? ? ? ? ? ?| ?112 ++++++----------------
> ?drivers/of/of_pci_irq.c ? ? ? ? ? ? ? ? ?| ? 92 ++++++++++++++++++
> ?drivers/pci/Makefile ? ? ? ? ? ? ? ? ? ? | ? ?2 +
> ?drivers/pci/hotplug/rpadlpar_core.c ? ? ?| ? ?2 +-
> ?drivers/pci/of.c ? ? ? ? ? ? ? ? ? ? ? ? | ? 61 ++++++++++++
> ?drivers/pci/probe.c ? ? ? ? ? ? ? ? ? ? ?| ? ?7 +-
> ?include/linux/of_pci.h ? ? ? ? ? ? ? ? ? | ? ?5 +
> ?include/linux/pci.h ? ? ? ? ? ? ? ? ? ? ?| ? 18 ++++
> ?22 files changed, 275 insertions(+), 376 deletions(-)
> ?create mode 100644 drivers/of/of_pci_irq.c
> ?create mode 100644 drivers/pci/of.c
>
> diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
> index 746df91..728f8d6 100644
> --- a/arch/microblaze/include/asm/pci-bridge.h
> +++ b/arch/microblaze/include/asm/pci-bridge.h
> @@ -105,19 +105,19 @@ struct pci_controller {
> ?};
>
> ?#ifdef CONFIG_PCI
> -static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
> +static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
> ?{
> - ? ? ? return bus->sysdata;
> + ? ? ? return dev->dev.of_node;
> ?}
>
> ?static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
> ?{
> - ? ? ? struct pci_controller *host;
> + ? ? ? return bus->dev.of_node;
> +}
>
> - ? ? ? if (bus->self)
> - ? ? ? ? ? ? ? return pci_device_to_OF_node(bus->self);
> - ? ? ? host = pci_bus_to_host(bus);
> - ? ? ? return host ? host->dn : NULL;
> +static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
> +{
> + ? ? ? return bus->sysdata;
> ?}
>
> ?static inline int isa_vaddr_is_ioport(void __iomem *address)
> diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
> index d0890d3..9bd01ec 100644
> --- a/arch/microblaze/include/asm/prom.h
> +++ b/arch/microblaze/include/asm/prom.h
> @@ -29,21 +29,6 @@
> ?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
> ?*/
> diff --git a/arch/microblaze/pci/pci_32.c b/arch/microblaze/pci/pci_32.c
> index 92728a6..2fa9506 100644
> --- a/arch/microblaze/pci/pci_32.c
> +++ b/arch/microblaze/pci/pci_32.c
> @@ -210,38 +210,6 @@ static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus)
> ? ? ? ?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)
> ?{
> @@ -315,6 +283,13 @@ pci_create_OF_bus_map(void)
> ? ? ? ?}
> ?}
>
> +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;
> @@ -332,7 +307,6 @@ static 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;
>
> diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
> index b90dbf8..3e68694 100644
> --- a/arch/powerpc/include/asm/pci-bridge.h
> +++ b/arch/powerpc/include/asm/pci-bridge.h
> @@ -169,18 +169,22 @@ static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
> ? ? ? ?return bus->sysdata;
> ?}
>
> -#ifndef CONFIG_PPC64
> +static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
> +{
> + ? ? ? return dev->dev.of_node;
> +}
>
> ?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;
> + ? ? ? return bus->dev.of_node;
> ?}
>
> +#ifndef CONFIG_PPC64
> +
> +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)
> ?{
> ? ? ? ?/* No specific ISA handling on ppc32 at this stage, it
> @@ -223,17 +227,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 +239,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);
>
> diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
> index 7d77909..1f52268 100644
> --- a/arch/powerpc/include/asm/pci.h
> +++ b/arch/powerpc/include/asm/pci.h
> @@ -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);
> diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
> index c189aa5..b823536 100644
> --- a/arch/powerpc/include/asm/prom.h
> +++ b/arch/powerpc/include/asm/prom.h
> @@ -22,20 +22,6 @@
>
> ?#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
> ?*/
> diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
> index 893af2a..a3c9277 100644
> --- a/arch/powerpc/kernel/pci-common.c
> +++ b/arch/powerpc/kernel/pci-common.c
> @@ -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;
>
> diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
> index bedb370..8658550 100644
> --- a/arch/powerpc/kernel/pci_32.c
> +++ b/arch/powerpc/kernel/pci_32.c
> @@ -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.
> diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
> index d225d99..8cb66a2 100644
> --- a/arch/powerpc/kernel/pci_dn.c
> +++ b/arch/powerpc/kernel/pci_dn.c
> @@ -143,53 +143,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.
> ?*
> diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
> index 1e89a72..fe0a5ad 100644
> --- a/arch/powerpc/kernel/pci_of_scan.c
> +++ b/arch/powerpc/kernel/pci_of_scan.c
> @@ -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);
> ? ? ? ? ? ? ? ?}
> ? ? ? ?}
> ?}
> diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
> index f33e08d..abe8d7e 100644
> --- a/arch/powerpc/platforms/powermac/pci.c
> +++ b/arch/powerpc/platforms/powermac/pci.c
> @@ -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;
>
> diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
> index 713dc91..e539d23 100644
> --- a/arch/sparc/kernel/pci.c
> +++ b/arch/sparc/kernel/pci.c
> @@ -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);
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index d06a637..cac63c9 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -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
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index f7861ed..dccb117 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -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
> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> index ac1ec54..ec7b060 100644
> --- a/drivers/of/of_pci.c
> +++ b/drivers/of/of_pci.c
> @@ -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(®[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
> index 0000000..ac1ec54
> --- /dev/null
> +++ b/drivers/of/of_pci_irq.c
> @@ -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);
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index 98d61c8..d5c3cb9 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -70,4 +70,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
> diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
> index 0830347..1d002b1 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)
> ? ? ? ?/* 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
> index 0000000..c94d37e
> --- /dev/null
> +++ b/drivers/pci/of.c
> @@ -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;
> +}
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 44cbbba..7964474 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -89,6 +89,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);
> ?}
>
> @@ -624,7 +625,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.. */
> @@ -1074,6 +1075,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);
> ?}
>
> @@ -1193,6 +1195,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;
> @@ -1445,6 +1449,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));
> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> index 85a27b6..f93e217 100644
> --- a/include/linux/of_pci.h
> +++ b/include/linux/of_pci.h
> @@ -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
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 96f70d7..f2a25f8 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1543,5 +1543,23 @@ 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);
> +
> +#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 */
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at ?http://www.tux.org/lkml/
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
On Sun, Apr 10, 2011 at 10:12 PM, Benjamin Herrenschmidt
<[email protected]> wrote:
> The generic code always get the device-node in the right place now
> so a single implementation will work for all archs
>
> Signed-off-by: Benjamin Herrenschmidt <[email protected]>
Patches 2-6 all look good to me.
Acked-by: Grant Likely <[email protected]>
> ---
> ?arch/microblaze/include/asm/pci-bridge.h | ? ?5 -----
> ?arch/powerpc/include/asm/pci-bridge.h ? ?| ? ?5 -----
> ?arch/x86/include/asm/prom.h ? ? ? ? ? ? ?| ? ?6 ------
> ?include/linux/pci.h ? ? ? ? ? ? ? ? ? ? ?| ? ?5 +++++
> ?4 files changed, 5 insertions(+), 16 deletions(-)
>
> diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
> index 0d74d03..242be57 100644
> --- a/arch/microblaze/include/asm/pci-bridge.h
> +++ b/arch/microblaze/include/asm/pci-bridge.h
> @@ -102,11 +102,6 @@ struct pci_controller {
> ?};
>
> ?#ifdef CONFIG_PCI
> -static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
> -{
> - ? ? ? return bus->dev.of_node;
> -}
> -
> ?static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
> ?{
> ? ? ? ?return bus->sysdata;
> diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
> index 578060e..90bd3ed 100644
> --- a/arch/powerpc/include/asm/pci-bridge.h
> +++ b/arch/powerpc/include/asm/pci-bridge.h
> @@ -169,11 +169,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)
> -{
> - ? ? ? return bus->dev.of_node;
> -}
> -
> ?#ifndef CONFIG_PPC64
>
> ?extern int pci_device_from_OF_node(struct device_node *node,
> diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h
> index dd6066a..df12870 100644
> --- a/arch/x86/include/asm/prom.h
> +++ b/arch/x86/include/asm/prom.h
> @@ -30,12 +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_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) { }
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 73dab8a..532c4e8 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1559,6 +1559,11 @@ 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) { }
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at ?http://www.tux.org/lkml/
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
Benjamin Herrenschmidt wrote:
> Here's a new batch. This time, I'm reasonably confident I build-tested the
> right commit-id's on sparc :-)
>
> To sort out the sparc problem I took a slightly different approach than
> discussed. I made the new code be of_pci.c (which I enabled on sparc)
> and put the old stuff into of_pci_irq.c (which should still be disabled
> there).
>
> I've also consolidated pci_bus_to_OF_node() while at it.
>
Acked-by: Michal Simek <[email protected]>
Michal
--
Michal Simek, Ing. (M.Eng)
w: http://www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel 2.6 Microblaze Linux - http://www.monstr.eu/fdt/
Microblaze U-BOOT custodian
On Mon, 2011-04-11 at 14:12 +1000, Benjamin Herrenschmidt wrote:
> Here's a new batch. This time, I'm reasonably confident I build-tested the
> right commit-id's on sparc :-)
>
> To sort out the sparc problem I took a slightly different approach than
> discussed. I made the new code be of_pci.c (which I enabled on sparc)
> and put the old stuff into of_pci_irq.c (which should still be disabled
> there).
>
> I've also consolidated pci_bus_to_OF_node() while at it.
Hi Jesse !
No significant changes (other than a rebase) nor new feedback since last
time, I've also added a few acks I got. But not worth spamming the list
with a re-post.
I'd like this to go into -next now so it can hit the next merge window,
unless somebody objects.
I've put the series in a branch "of-pci" of my powerpc.git repo at:
git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git of-pci
Please let me know if you're ok (and maybe give me Ack's) and I'll ask
Stephen to add it to next.
Cheers,
Ben.
On Tue, 07 Jun 2011 15:58:43 +1000
Benjamin Herrenschmidt <[email protected]> wrote:
> On Mon, 2011-04-11 at 14:12 +1000, Benjamin Herrenschmidt wrote:
> > Here's a new batch. This time, I'm reasonably confident I build-tested the
> > right commit-id's on sparc :-)
> >
> > To sort out the sparc problem I took a slightly different approach than
> > discussed. I made the new code be of_pci.c (which I enabled on sparc)
> > and put the old stuff into of_pci_irq.c (which should still be disabled
> > there).
> >
> > I've also consolidated pci_bus_to_OF_node() while at it.
>
> Hi Jesse !
>
> No significant changes (other than a rebase) nor new feedback since last
> time, I've also added a few acks I got. But not worth spamming the list
> with a re-post.
>
> I'd like this to go into -next now so it can hit the next merge window,
> unless somebody objects.
>
> I've put the series in a branch "of-pci" of my powerpc.git repo at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git of-pci
>
> Please let me know if you're ok (and maybe give me Ack's) and I'll ask
> Stephen to add it to next.
Yeah, the generic bits look good to me, you can add my
Acked-by: Jesse Barnes <[email protected]>
Thanks,
--
Jesse Barnes, Intel Open Source Technology Center
> > No significant changes (other than a rebase) nor new feedback since last
> > time, I've also added a few acks I got. But not worth spamming the list
> > with a re-post.
> >
> > I'd like this to go into -next now so it can hit the next merge window,
> > unless somebody objects.
> >
> > I've put the series in a branch "of-pci" of my powerpc.git repo at:
> >
> > git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git of-pci
> >
> > Please let me know if you're ok (and maybe give me Ack's) and I'll ask
> > Stephen to add it to next.
>
> Yeah, the generic bits look good to me, you can add my
> Acked-by: Jesse Barnes <[email protected]>
Great. Will do. I'll ask Stephen to that that in -next then and will ask
Linus to pull directly at the next merge window, separately from
powerpc.git (tho I might actually end up pulling that tree into
powerpc.git too as I might end up with stuff that depends on it).
Cheers,
Ben.
On Wed, 2011-06-08 at 07:37 +1000, Benjamin Herrenschmidt wrote:
> > > No significant changes (other than a rebase) nor new feedback since last
> > > time, I've also added a few acks I got. But not worth spamming the list
> > > with a re-post.
> > >
> > > I'd like this to go into -next now so it can hit the next merge window,
> > > unless somebody objects.
> > >
> > > I've put the series in a branch "of-pci" of my powerpc.git repo at:
> > >
> > > git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git of-pci
> > >
> > > Please let me know if you're ok (and maybe give me Ack's) and I'll ask
> > > Stephen to add it to next.
> >
> > Yeah, the generic bits look good to me, you can add my
> > Acked-by: Jesse Barnes <[email protected]>
>
> Great. Will do. I'll ask Stephen to that that in -next then and will ask
> Linus to pull directly at the next merge window, separately from
> powerpc.git (tho I might actually end up pulling that tree into
> powerpc.git too as I might end up with stuff that depends on it).
Allright, Stephen, can you stick this into -next please ?
git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git of-pci
I've added Jesse's acks.
Thanks !
Cheers,
Ben.
Hi Ben,
On Wed, 08 Jun 2011 10:06:05 +1000 Benjamin Herrenschmidt <[email protected]> wrote:
>
> On Wed, 2011-06-08 at 07:37 +1000, Benjamin Herrenschmidt wrote:
> > > > No significant changes (other than a rebase) nor new feedback since last
> > > > time, I've also added a few acks I got. But not worth spamming the list
> > > > with a re-post.
> > > >
> > > > I'd like this to go into -next now so it can hit the next merge window,
> > > > unless somebody objects.
> > > >
> > > > I've put the series in a branch "of-pci" of my powerpc.git repo at:
> > > >
> > > > git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git of-pci
> > > >
> > > > Please let me know if you're ok (and maybe give me Ack's) and I'll ask
> > > > Stephen to add it to next.
> > >
> > > Yeah, the generic bits look good to me, you can add my
> > > Acked-by: Jesse Barnes <[email protected]>
> >
> > Great. Will do. I'll ask Stephen to that that in -next then and will ask
> > Linus to pull directly at the next merge window, separately from
> > powerpc.git (tho I might actually end up pulling that tree into
> > powerpc.git too as I might end up with stuff that depends on it).
>
> Allright, Stephen, can you stick this into -next please ?
>
> git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git of-pci
>
> I've added Jesse's acks.
OK, I have added this today.
Thanks for adding your subsystem tree as a participant of linux-next. As
you may know, this is not a judgment of your code. The purpose of
linux-next is for integration testing and to lower the impact of
conflicts between subsystems in the next merge window.
You will need to ensure that the patches/commits in your tree/series have
been:
* submitted under GPL v2 (or later) and include the Contributor's
Signed-off-by,
* posted to the relevant mailing list,
* reviewed by you (or another maintainer of your subsystem tree),
* successfully unit tested, and
* destined for the current or next Linux merge window.
Basically, this should be just what you would send to Linus (or ask him
to fetch). It is allowed to be rebased if you deem it necessary.
--
Cheers,
Stephen Rothwell
[email protected]
Legal Stuff:
By participating in linux-next, your subsystem tree contributions are
public and will be included in the linux-next trees. You may be sent
e-mail messages indicating errors or other issues when the
patches/commits from your subsystem tree are merged and tested in
linux-next. These messages may also be cross-posted to the linux-next
mailing list, the linux-kernel mailing list, etc. The linux-next tree
project and IBM (my employer) make no warranties regarding the linux-next
project, the testing procedures, the results, the e-mails, etc. If you
don't agree to these ground rules, let me know and I'll remove your tree
from participation in linux-next.