summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/pci_32.c
diff options
context:
space:
mode:
authorTom Arbuckle <tom.d.arbuckle@gmail.com>2009-02-11 10:41:48 +0000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-02-23 10:48:57 +1100
commitf81786913aa0ca27a3230f30d099e9613d0d7973 (patch)
tree2431bff1643e0105985fd00bc68ddea428782cd7 /arch/powerpc/kernel/pci_32.c
parent16c57b3620d77e0bc981da5ef32beae730512684 (diff)
powerpc/pci: Fix PCI<->OF matching of old style multifunc devices
Old OF variants used to create a 'dummy' parent node "multifunc-device" for devices with more than one PCI function. Our code that matches OF nodes to PCI devices dealt with that in one place but not in another, this fixes it. This has the practical effect of fixing interrupt routing of multifunction PCI cards on some older PowerMac machines. Signed-off-by: Tom Arbuckle <tom.d.arbuckle@gmail.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/pci_32.c')
-rw-r--r--arch/powerpc/kernel/pci_32.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index c6368506455..d473634e39e 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -218,16 +218,23 @@ scan_OF_pci_childs(struct device_node *parent, pci_OF_scan_iterator filter, void
static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
unsigned int devfn)
{
- struct device_node *np;
+ 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 == NULL || psize < 4)
- continue;
- if (((reg[0] >> 8) & 0xff) == devfn)
+ 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;
}