summaryrefslogtreecommitdiff
path: root/target/linux
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux')
-rw-r--r--target/linux/generic/patches-3.8/031-pci-of-remove-weak-annotation-of-pcibios_get_phb_of_.patch150
-rw-r--r--target/linux/generic/patches-3.8/032-MIPS-implement-pcibios_get_phb_of_node.patch47
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);