diff options
2 files changed, 197 insertions, 0 deletions
diff --git a/target/linux/generic/patches-3.8/031-pci-of-remove-weak-annotation-of-pcibios_get_phb_of_.patch b/target/linux/generic/patches-3.8/031-pci-of-remove-weak-annotation-of-pcibios_get_phb_of_.patch new file mode 100644 index 0000000000..a439d1db81 --- /dev/null +++ b/target/linux/generic/patches-3.8/031-pci-of-remove-weak-annotation-of-pcibios_get_phb_of_.patch @@ -0,0 +1,150 @@ +From 61cb343b4ac20d2d957811cd492fec770646dda8 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Wed, 3 Apr 2013 19:47:50 +0200 +Subject: [PATCH 1/2] pci/of: remove weak annotation of + pcibios_get_phb_of_node + +Due to the __weak annotation in the forward declaration +of the 'pcibios_get_phb_of_node' function GCC will emit +a weak symbol for this functions even if the actual +implementation does not use the weak attribute. + +If an architecture tries to override the function +by providing its own implementation there will be +multiple weak symbols with the same name in the +object files. When the kernel is linked from the +object files the linking order determines which +implementation will be used in the final image. + +On x86 and on powerpc the architecture specific +version gets used: + + $ readelf -s arch/x86/kernel/built-in.o drivers/pci/built-in.o \ + vmlinux.o | grep pcibios_get_phb_of_node + 3338: 00029b80 86 FUNC WEAK DEFAULT 1 pcibios_get_phb_of_node + 1701: 00012710 77 FUNC WEAK DEFAULT 1 pcibios_get_phb_of_node + 52072: 0002a170 86 FUNC WEAK DEFAULT 1 pcibios_get_phb_of_node + $ + + $ powerpc-openwrt-linux-uclibc-readelf -s arch/powerpc/kernel/built-in.o \ + drivers/pci/built-in.o vmlinux.o | grep pcibios_get_phb_of_node + 1001: 0000cbb8 12 FUNC WEAK DEFAULT 1 pcibios_get_phb_of_node + 1484: 0001471c 88 FUNC WEAK DEFAULT 1 pcibios_get_phb_of_node + 28652: 0000d6f8 12 FUNC WEAK DEFAULT 1 pcibios_get_phb_of_node + $ + +However on MIPS, the linker puts the default +implementation into the final image: + + $ mipsel-openwrt-linux-readelf -s arch/mips/pci/built-in.o \ + drivers/pci/built-in.o vmlinux.o | grep pcibios_get_phb_of_node + 86: 0000046c 12 FUNC WEAK DEFAULT 2 pcibios_get_phb_of_node + 1430: 00012e2c 104 FUNC WEAK DEFAULT 2 pcibios_get_phb_of_node + 31898: 0017e4ec 104 FUNC WEAK DEFAULT 2 pcibios_get_phb_of_node + $ + +Rename the default implementation and remove the +__weak annotation of that. This ensures that there +will be no multiple weak symbols with the same name +in the object files. In order to keep the expected +behaviour, call the architecture specific function +if the weak symbol is resolved. + +Also move the renamed function to the top instead +of adding a new forward declaration for that. + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- +Notes: + +Unfortunately I'm not a binutils/gcc expert, so +I don't know if this is the expected behaviour +of those or not. + +Removing the __weak annotation from the forward +declaration of 'pcibios_get_phb_of_node' in +'include/linux/pci.h' also fixes the problem. + +The microblaze architecture also provides its own +implementation. The behaviour of that is not tested +but I assume that the linker chooses the arch specific +implementation on that as well similarly to the +x86/powerpc. + +The MIPS version is implemented in the followup +patch. + +Removing the __weak annotation from the forward +declaration of 'pcibios_get_phb_of_node' in +'include/linux/pci.h' also fixes the problem. + +-Gabor +--- + drivers/pci/of.c | 41 +++++++++++++++++++++++------------------ + 1 file changed, 23 insertions(+), 18 deletions(-) + +--- a/drivers/pci/of.c ++++ b/drivers/pci/of.c +@@ -15,10 +15,32 @@ + #include <linux/of_pci.h> + #include "pci.h" + ++static struct device_node *__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; ++ ++ if (pcibios_get_phb_of_node) ++ return pcibios_get_phb_of_node(bus); ++ ++ /* 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 && bus->bridge->parent->of_node) ++ return of_node_get(bus->bridge->parent->of_node); ++ ++ return NULL; ++} ++ + 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); + } +@@ -32,7 +54,7 @@ void pci_release_of_node(struct pci_dev + void pci_set_bus_of_node(struct pci_bus *bus) + { + if (bus->self == NULL) +- bus->dev.of_node = pcibios_get_phb_of_node(bus); ++ bus->dev.of_node = __pcibios_get_phb_of_node(bus); + else + bus->dev.of_node = of_node_get(bus->self->dev.of_node); + } +@@ -42,20 +64,3 @@ void pci_release_bus_of_node(struct pci_ + 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 && bus->bridge->parent->of_node) +- return of_node_get(bus->bridge->parent->of_node); +- return NULL; +-} diff --git a/target/linux/generic/patches-3.8/032-MIPS-implement-pcibios_get_phb_of_node.patch b/target/linux/generic/patches-3.8/032-MIPS-implement-pcibios_get_phb_of_node.patch new file mode 100644 index 0000000000..772816558e --- /dev/null +++ b/target/linux/generic/patches-3.8/032-MIPS-implement-pcibios_get_phb_of_node.patch @@ -0,0 +1,47 @@ +From fe17cba0e4efb6cf6d1e4e79fa4c6e062fe32b39 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Wed, 3 Apr 2013 19:28:50 +0200 +Subject: [PATCH 2/2] MIPS: implement pcibios_get_phb_of_node + +The of_node field of the device assigned to a +PCI bus is used during scanning of the PCI bus. +However on MIPS, the of_node field is assigned +only after the bus has been scanned. + +Implement the architecture specific version of +'pcibios_get_phb_of_node'. Which ensures that the +PCI driver core will initialize the of_node field +before starting the scan. + +Also remove the local assignment of bus->dev.of_node, +it is not needed after the patch. + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + arch/mips/pci/pci.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/arch/mips/pci/pci.c ++++ b/arch/mips/pci/pci.c +@@ -115,7 +115,6 @@ static void pcibios_scanbus(struct pci_c + pci_bus_assign_resources(bus); + pci_enable_bridges(bus); + } +- bus->dev.of_node = hose->of_node; + } + } + +@@ -169,6 +168,13 @@ void pci_load_of_ranges(struct pci_contr + } + } + } ++ ++struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus) ++{ ++ struct pci_controller *hose = bus->sysdata; ++ ++ return of_node_get(hose->of_node); ++} + #endif + + static DEFINE_MUTEX(pci_scan_mutex); |