From 4b6ba8aacbb3185703b797286547d0f8f3859b02 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 26 Oct 2010 15:07:13 -0700 Subject: of/net: Move of_get_mac_address() to a common source file. There are two identical implementations of of_get_mac_address(), one each in arch/powerpc/kernel/prom_parse.c and arch/microblaze/kernel/prom_parse.c. Move this function to a new common file of_net.{c,h} and adjust all the callers to include the new header. Signed-off-by: David Daney [grant.likely@secretlab.ca: protect header with #ifdef] Signed-off-by: Grant Likely --- drivers/of/Kconfig | 4 ++++ drivers/of/Makefile | 1 + drivers/of/of_net.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 drivers/of/of_net.c (limited to 'drivers/of') diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index aa675ebd8eb3..e4b93a0a15d2 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -49,6 +49,10 @@ config OF_I2C help OpenFirmware I2C accessors +config OF_NET + depends on NETDEVICES + def_bool y + config OF_SPI def_tristate SPI depends on SPI && !SPARC diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 7888155bea08..3ab21a0a4907 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -6,5 +6,6 @@ obj-$(CONFIG_OF_IRQ) += irq.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o +obj-$(CONFIG_OF_NET) += of_net.o obj-$(CONFIG_OF_SPI) += of_spi.o obj-$(CONFIG_OF_MDIO) += of_mdio.o diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c new file mode 100644 index 000000000000..86f334a2769c --- /dev/null +++ b/drivers/of/of_net.c @@ -0,0 +1,48 @@ +/* + * OF helpers for network devices. + * + * This file is released under the GPLv2 + * + * Initially copied out of arch/powerpc/kernel/prom_parse.c + */ +#include +#include +#include + +/** + * Search the device tree for the best MAC address to use. 'mac-address' is + * checked first, because that is supposed to contain to "most recent" MAC + * address. If that isn't set, then 'local-mac-address' is checked next, + * because that is the default address. If that isn't set, then the obsolete + * 'address' is checked, just in case we're using an old device tree. + * + * Note that the 'address' property is supposed to contain a virtual address of + * the register set, but some DTS files have redefined that property to be the + * MAC address. + * + * All-zero MAC addresses are rejected, because those could be properties that + * exist in the device tree, but were not set by U-Boot. For example, the + * DTS could define 'mac-address' and 'local-mac-address', with zero MAC + * addresses. Some older U-Boots only initialized 'local-mac-address'. In + * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists + * but is all zeros. +*/ +const void *of_get_mac_address(struct device_node *np) +{ + struct property *pp; + + pp = of_find_property(np, "mac-address", NULL); + if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) + return pp->value; + + pp = of_find_property(np, "local-mac-address", NULL); + if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) + return pp->value; + + pp = of_find_property(np, "address", NULL); + if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) + return pp->value; + + return NULL; +} +EXPORT_SYMBOL(of_get_mac_address); -- cgit v1.2.3 From 0131d8973c8b9bd9d40fee8fae24eab24821efdb Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 1 Dec 2010 10:54:46 +0100 Subject: of/address: use proper endianess in get_flags This patch changes u32 to __be32 for all "ranges", "prop" and "addr" and such. Those variables are pointing to the device tree which contains integers in big endian format. Most functions are doing it right because of_read_number() is doing the right thing for them. of_bus_isa_get_flags(), of_bus_pci_get_flags() and of_bus_isa_map() were accessing the data directly and were doing it wrong. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Benjamin Herrenschmidt Signed-off-by: Grant Likely --- drivers/of/address.c | 54 +++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/address.c b/drivers/of/address.c index 3a1c7e70b192..b4559c58c095 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -12,13 +12,13 @@ (ns) > 0) static struct of_bus *of_match_bus(struct device_node *np); -static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, - u64 size, unsigned int flags, +static int __of_address_to_resource(struct device_node *dev, + const __be32 *addrp, u64 size, unsigned int flags, struct resource *r); /* Debug utility */ #ifdef DEBUG -static void of_dump_addr(const char *s, const u32 *addr, int na) +static void of_dump_addr(const char *s, const __be32 *addr, int na) { printk(KERN_DEBUG "%s", s); while (na--) @@ -26,7 +26,7 @@ static void of_dump_addr(const char *s, const u32 *addr, int na) printk("\n"); } #else -static void of_dump_addr(const char *s, const u32 *addr, int na) { } +static void of_dump_addr(const char *s, const __be32 *addr, int na) { } #endif /* Callbacks for bus specific translators */ @@ -36,10 +36,10 @@ struct of_bus { int (*match)(struct device_node *parent); void (*count_cells)(struct device_node *child, int *addrc, int *sizec); - u64 (*map)(u32 *addr, const u32 *range, + u64 (*map)(u32 *addr, const __be32 *range, int na, int ns, int pna); int (*translate)(u32 *addr, u64 offset, int na); - unsigned int (*get_flags)(const u32 *addr); + unsigned int (*get_flags)(const __be32 *addr); }; /* @@ -55,7 +55,7 @@ static void of_bus_default_count_cells(struct device_node *dev, *sizec = of_n_size_cells(dev); } -static u64 of_bus_default_map(u32 *addr, const u32 *range, +static u64 of_bus_default_map(u32 *addr, const __be32 *range, int na, int ns, int pna) { u64 cp, s, da; @@ -85,7 +85,7 @@ static int of_bus_default_translate(u32 *addr, u64 offset, int na) return 0; } -static unsigned int of_bus_default_get_flags(const u32 *addr) +static unsigned int of_bus_default_get_flags(const __be32 *addr) { return IORESOURCE_MEM; } @@ -110,10 +110,10 @@ static void of_bus_pci_count_cells(struct device_node *np, *sizec = 2; } -static unsigned int of_bus_pci_get_flags(const u32 *addr) +static unsigned int of_bus_pci_get_flags(const __be32 *addr) { unsigned int flags = 0; - u32 w = addr[0]; + u32 w = be32_to_cpup(addr); switch((w >> 24) & 0x03) { case 0x01: @@ -129,7 +129,8 @@ static unsigned int of_bus_pci_get_flags(const u32 *addr) return flags; } -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna) +static u64 of_bus_pci_map(u32 *addr, const __be32 *range, int na, int ns, + int pna) { u64 cp, s, da; unsigned int af, rf; @@ -160,7 +161,7 @@ static int of_bus_pci_translate(u32 *addr, u64 offset, int na) return of_bus_default_translate(addr + 1, offset, na - 1); } -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, +const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags) { const __be32 *prop; @@ -207,7 +208,7 @@ EXPORT_SYMBOL(of_get_pci_address); int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r) { - const u32 *addrp; + const __be32 *addrp; u64 size; unsigned int flags; @@ -237,12 +238,13 @@ static void of_bus_isa_count_cells(struct device_node *child, *sizec = 1; } -static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna) +static u64 of_bus_isa_map(u32 *addr, const __be32 *range, int na, int ns, + int pna) { u64 cp, s, da; /* Check address type match */ - if ((addr[0] ^ range[0]) & 0x00000001) + if ((addr[0] ^ range[0]) & cpu_to_be32(1)) return OF_BAD_ADDR; /* Read address values, skipping high cell */ @@ -264,10 +266,10 @@ static int of_bus_isa_translate(u32 *addr, u64 offset, int na) return of_bus_default_translate(addr + 1, offset, na - 1); } -static unsigned int of_bus_isa_get_flags(const u32 *addr) +static unsigned int of_bus_isa_get_flags(const __be32 *addr) { unsigned int flags = 0; - u32 w = addr[0]; + u32 w = be32_to_cpup(addr); if (w & 1) flags |= IORESOURCE_IO; @@ -330,7 +332,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, struct of_bus *pbus, u32 *addr, int na, int ns, int pna, const char *rprop) { - const u32 *ranges; + const __be32 *ranges; unsigned int rlen; int rone; u64 offset = OF_BAD_ADDR; @@ -398,7 +400,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, * that can be mapped to a cpu physical address). This is not really specified * that way, but this is traditionally the way IBM at least do things */ -u64 __of_translate_address(struct device_node *dev, const u32 *in_addr, +u64 __of_translate_address(struct device_node *dev, const __be32 *in_addr, const char *rprop) { struct device_node *parent = NULL; @@ -475,22 +477,22 @@ u64 __of_translate_address(struct device_node *dev, const u32 *in_addr, return result; } -u64 of_translate_address(struct device_node *dev, const u32 *in_addr) +u64 of_translate_address(struct device_node *dev, const __be32 *in_addr) { return __of_translate_address(dev, in_addr, "ranges"); } EXPORT_SYMBOL(of_translate_address); -u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr) +u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) { return __of_translate_address(dev, in_addr, "dma-ranges"); } EXPORT_SYMBOL(of_translate_dma_address); -const u32 *of_get_address(struct device_node *dev, int index, u64 *size, +const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags) { - const u32 *prop; + const __be32 *prop; unsigned int psize; struct device_node *parent; struct of_bus *bus; @@ -525,8 +527,8 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size, } EXPORT_SYMBOL(of_get_address); -static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, - u64 size, unsigned int flags, +static int __of_address_to_resource(struct device_node *dev, + const __be32 *addrp, u64 size, unsigned int flags, struct resource *r) { u64 taddr; @@ -564,7 +566,7 @@ static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, int of_address_to_resource(struct device_node *dev, int index, struct resource *r) { - const u32 *addrp; + const __be32 *addrp; u64 size; unsigned int flags; -- cgit v1.2.3 From 194588604765ac803f98fb9d19a36f6b835f4620 Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 27 Oct 2010 18:03:47 -0700 Subject: of/mdio: Fix some endianness problems. In of_mdiobus_register(), the __be32 *addr variable is dereferenced. This will not work on little-endian targets. Also since it is unsigned, checking for less than zero is redundant. Fix these two issues. Signed-off-by: David Daney [grant.likely@secretlab.ca: removed goto] Signed-off-by: Grant Likely --- drivers/of/of_mdio.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 1fce00eb421b..dcd7857784f2 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -52,27 +52,35 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) /* Loop over the child nodes and register a phy_device for each one */ for_each_child_of_node(np, child) { - const __be32 *addr; + const __be32 *paddr; + u32 addr; int len; /* A PHY must have a reg property in the range [0-31] */ - addr = of_get_property(child, "reg", &len); - if (!addr || len < sizeof(*addr) || *addr >= 32 || *addr < 0) { + paddr = of_get_property(child, "reg", &len); + if (!paddr || len < sizeof(*paddr)) { dev_err(&mdio->dev, "%s has invalid PHY address\n", child->full_name); continue; } + addr = be32_to_cpup(paddr); + if (addr >= 32) { + dev_err(&mdio->dev, "%s PHY address %i is too large\n", + child->full_name, addr); + continue; + } + if (mdio->irq) { - mdio->irq[*addr] = irq_of_parse_and_map(child, 0); - if (!mdio->irq[*addr]) - mdio->irq[*addr] = PHY_POLL; + mdio->irq[addr] = irq_of_parse_and_map(child, 0); + if (!mdio->irq[addr]) + mdio->irq[addr] = PHY_POLL; } - phy = get_phy_device(mdio, be32_to_cpup(addr)); + phy = get_phy_device(mdio, addr); if (!phy || IS_ERR(phy)) { dev_err(&mdio->dev, "error probing PHY at address %i\n", - *addr); + addr); continue; } phy_scan_fixups(phy); @@ -91,7 +99,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) } dev_dbg(&mdio->dev, "registered phy %s at address %i\n", - child->name, *addr); + child->name, addr); } return 0; -- cgit v1.2.3 From e6ce1324e4f08b0d984340201a125806dae0e9a6 Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Thu, 18 Nov 2010 15:54:56 -0800 Subject: of/flattree: Add Kconfig for EARLY_FLATTREE The device tree code is now in two pieces: some which can be used generically on any platform which selects CONFIG_OF_FLATTREE, and some early which is used at boot time on only a few architectures. This patch segregates the early code so that only those architectures which care about it need compile it. This also means that some of the requirements in the early code (such as a cmd_line variable) that most architectures (e.g. X86) don't provide can be ignored. Signed-off-by: Stephen Neuendorffer [grant.likely@secretlab.ca: remove extra blank line addition] [grant.likely@secretlab.ca: fixed incorrect #ifdef CONFIG_EARLY_FLATTREE check] [grant.likely@secretlab.ca: Made OF_EARLY_FLATTREE select instead of depend on OF_FLATTREE] Signed-off-by: Grant Likely --- drivers/of/Kconfig | 4 ++++ drivers/of/fdt.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'drivers/of') diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index e4b93a0a15d2..3c6e100a3ad0 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -19,6 +19,10 @@ config OF_FLATTREE bool select DTC +config OF_EARLY_FLATTREE + bool + select OF_FLATTREE + config OF_PROMTREE bool diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index c1360e02f921..2ebacf14e7de 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -27,6 +27,8 @@ int __initdata dt_root_size_cells; struct boot_param_header *initial_boot_params; +#ifdef CONFIG_OF_EARLY_FLATTREE + char *find_flat_dt_string(u32 offset) { return ((char *)initial_boot_params) + @@ -604,3 +606,5 @@ void __init unflatten_device_tree(void) pr_debug(" <- unflatten_device_tree()\n"); } + +#endif /* CONFIG_OF_EARLY_FLATTREE */ -- cgit v1.2.3 From 9706a36e35c4ce04f28a62cfe1205b4e3b0dd13c Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Thu, 18 Nov 2010 15:54:59 -0800 Subject: of/flattree: Add non-boottime device tree functions In preparation for providing run-time handling of device trees, factor out some of the basic functions so that they take an arbitrary blob, rather than relying on the single boot-time tree. V2: - functions have of_fdt_* names - removed find_flat_dt_string - blob argument is first Signed-off-by: Stephen Neuendorffer Signed-off-by: Grant Likely --- drivers/of/fdt.c | 133 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 79 insertions(+), 54 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 2ebacf14e7de..10eab21076ea 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -22,6 +22,82 @@ #include +char *of_fdt_get_string(struct boot_param_header *blob, u32 offset) +{ + return ((char *)blob) + + be32_to_cpu(blob->off_dt_strings) + offset; +} + +/** + * of_fdt_get_property - Given a node in the given flat blob, return + * the property ptr + */ +void *of_fdt_get_property(struct boot_param_header *blob, + unsigned long node, const char *name, + unsigned long *size) +{ + unsigned long p = node; + + do { + u32 tag = be32_to_cpup((__be32 *)p); + u32 sz, noff; + const char *nstr; + + p += 4; + if (tag == OF_DT_NOP) + continue; + if (tag != OF_DT_PROP) + return NULL; + + sz = be32_to_cpup((__be32 *)p); + noff = be32_to_cpup((__be32 *)(p + 4)); + p += 8; + if (be32_to_cpu(blob->version) < 0x10) + p = ALIGN(p, sz >= 8 ? 8 : 4); + + nstr = of_fdt_get_string(blob, noff); + if (nstr == NULL) { + pr_warning("Can't find property index name !\n"); + return NULL; + } + if (strcmp(name, nstr) == 0) { + if (size) + *size = sz; + return (void *)p; + } + p += sz; + p = ALIGN(p, 4); + } while (1); +} + +/** + * of_fdt_is_compatible - Return true if given node from the given blob has + * compat in its compatible list + * @blob: A device tree blob + * @node: node to test + * @compat: compatible string to compare with compatible list. + */ +int of_fdt_is_compatible(struct boot_param_header *blob, + unsigned long node, const char *compat) +{ + const char *cp; + unsigned long cplen, l; + + cp = of_fdt_get_property(blob, node, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (of_compat_cmp(cp, compat, strlen(compat)) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + +/* Everything below here references initial_boot_params directly. */ int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; @@ -29,12 +105,6 @@ struct boot_param_header *initial_boot_params; #ifdef CONFIG_OF_EARLY_FLATTREE -char *find_flat_dt_string(u32 offset) -{ - return ((char *)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_strings) + offset; -} - /** * of_scan_flat_dt - scan flattened tree blob and call callback on each. * @it: callback function @@ -123,38 +193,7 @@ unsigned long __init of_get_flat_dt_root(void) void *__init of_get_flat_dt_prop(unsigned long node, const char *name, unsigned long *size) { - unsigned long p = node; - - do { - u32 tag = be32_to_cpup((__be32 *)p); - u32 sz, noff; - const char *nstr; - - p += 4; - if (tag == OF_DT_NOP) - continue; - if (tag != OF_DT_PROP) - return NULL; - - sz = be32_to_cpup((__be32 *)p); - noff = be32_to_cpup((__be32 *)(p + 4)); - p += 8; - if (be32_to_cpu(initial_boot_params->version) < 0x10) - p = ALIGN(p, sz >= 8 ? 8 : 4); - - nstr = find_flat_dt_string(noff); - if (nstr == NULL) { - pr_warning("Can't find property index name !\n"); - return NULL; - } - if (strcmp(name, nstr) == 0) { - if (size) - *size = sz; - return (void *)p; - } - p += sz; - p = ALIGN(p, 4); - } while (1); + return of_fdt_get_property(initial_boot_params, node, name, size); } /** @@ -164,21 +203,7 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, */ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) { - const char *cp; - unsigned long cplen, l; - - cp = of_get_flat_dt_prop(node, "compatible", &cplen); - if (cp == NULL) - return 0; - while (cplen > 0) { - if (of_compat_cmp(cp, compat, strlen(compat)) == 0) - return 1; - l = strlen(cp) + 1; - cp += l; - cplen -= l; - } - - return 0; + return of_fdt_is_compatible(initial_boot_params, node, compat); } static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, @@ -303,7 +328,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, if (be32_to_cpu(initial_boot_params->version) < 0x10) *p = ALIGN(*p, sz >= 8 ? 8 : 4); - pname = find_flat_dt_string(noff); + pname = of_fdt_get_string(initial_boot_params, noff); if (pname == NULL) { pr_info("Can't find property name in list !\n"); break; -- cgit v1.2.3 From a40d6c4cf12d87980c10b230df435d0f56adc40b Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Thu, 18 Nov 2010 15:55:00 -0800 Subject: of/flattree: Refactor unflatten_dt_node unflatten_dt_node is a helper function that does most of the work to convert a device tree blob into tree of device nodes. This code now uses a passed-in blob instead of using the single boot-time blob, allowing it to be called in more contexts. Signed-off-by: Stephen Neuendorffer Signed-off-by: Grant Likely --- drivers/of/fdt.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 10eab21076ea..cf74e546faf2 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -206,7 +206,7 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) return of_fdt_is_compatible(initial_boot_params, node, compat); } -static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, +static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size, unsigned long align) { void *res; @@ -220,16 +220,18 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, /** * unflatten_dt_node - Alloc and populate a device_node from the flat tree + * @blob: The parent device tree blob * @p: pointer to node in flat tree * @dad: Parent struct device_node * @allnextpp: pointer to ->allnext from last allocated device_node * @fpsize: Size of the node path up at the current depth. */ -unsigned long __init unflatten_dt_node(unsigned long mem, - unsigned long *p, - struct device_node *dad, - struct device_node ***allnextpp, - unsigned long fpsize) +unsigned long unflatten_dt_node(struct boot_param_header *blob, + unsigned long mem, + unsigned long *p, + struct device_node *dad, + struct device_node ***allnextpp, + unsigned long fpsize) { struct device_node *np; struct property *pp, **prev_pp = NULL; @@ -325,10 +327,10 @@ unsigned long __init unflatten_dt_node(unsigned long mem, sz = be32_to_cpup((__be32 *)(*p)); noff = be32_to_cpup((__be32 *)((*p) + 4)); *p += 8; - if (be32_to_cpu(initial_boot_params->version) < 0x10) + if (be32_to_cpu(blob->version) < 0x10) *p = ALIGN(*p, sz >= 8 ? 8 : 4); - pname = of_fdt_get_string(initial_boot_params, noff); + pname = of_fdt_get_string(blob, noff); if (pname == NULL) { pr_info("Can't find property name in list !\n"); break; @@ -407,7 +409,8 @@ unsigned long __init unflatten_dt_node(unsigned long mem, if (tag == OF_DT_NOP) *p += 4; else - mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); + mem = unflatten_dt_node(blob, mem, p, np, allnextpp, + fpsize); tag = be32_to_cpup((__be32 *)(*p)); } if (tag != OF_DT_END_NODE) { @@ -599,7 +602,8 @@ void __init unflatten_device_tree(void) /* First pass, scan for size */ start = ((unsigned long)initial_boot_params) + be32_to_cpu(initial_boot_params->off_dt_struct); - size = unflatten_dt_node(0, &start, NULL, NULL, 0); + size = unflatten_dt_node(initial_boot_params, 0, &start, + NULL, NULL, 0); size = (size | 3) + 1; pr_debug(" size is %lx, allocating...\n", size); @@ -616,7 +620,8 @@ void __init unflatten_device_tree(void) /* Second pass, do actual unflattening */ start = ((unsigned long)initial_boot_params) + be32_to_cpu(initial_boot_params->off_dt_struct); - unflatten_dt_node(mem, &start, NULL, &allnextp, 0); + unflatten_dt_node(initial_boot_params, mem, &start, + NULL, &allnextp, 0); if (be32_to_cpup((__be32 *)start) != OF_DT_END) pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) -- cgit v1.2.3 From 57d00ecf90cc9854973da2960012b734acc26e51 Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Thu, 18 Nov 2010 15:55:01 -0800 Subject: of/flattree: Reorder unflatten_dt_node Move unflatten_dt_node to be grouped with non-__init functions. Signed-off-by: Stephen Neuendorffer Signed-off-by: Grant Likely --- drivers/of/fdt.c | 218 +++++++++++++++++++++++++++---------------------------- 1 file changed, 109 insertions(+), 109 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index cf74e546faf2..71edc9cecd62 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -97,115 +97,6 @@ int of_fdt_is_compatible(struct boot_param_header *blob, return 0; } -/* Everything below here references initial_boot_params directly. */ -int __initdata dt_root_addr_cells; -int __initdata dt_root_size_cells; - -struct boot_param_header *initial_boot_params; - -#ifdef CONFIG_OF_EARLY_FLATTREE - -/** - * of_scan_flat_dt - scan flattened tree blob and call callback on each. - * @it: callback function - * @data: context data pointer - * - * This function is used to scan the flattened device-tree, it is - * used to extract the memory information at boot before we can - * unflatten the tree - */ -int __init of_scan_flat_dt(int (*it)(unsigned long node, - const char *uname, int depth, - void *data), - void *data) -{ - unsigned long p = ((unsigned long)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_struct); - int rc = 0; - int depth = -1; - - do { - u32 tag = be32_to_cpup((__be32 *)p); - char *pathp; - - p += 4; - if (tag == OF_DT_END_NODE) { - depth--; - continue; - } - if (tag == OF_DT_NOP) - continue; - if (tag == OF_DT_END) - break; - if (tag == OF_DT_PROP) { - u32 sz = be32_to_cpup((__be32 *)p); - p += 8; - if (be32_to_cpu(initial_boot_params->version) < 0x10) - p = ALIGN(p, sz >= 8 ? 8 : 4); - p += sz; - p = ALIGN(p, 4); - continue; - } - if (tag != OF_DT_BEGIN_NODE) { - pr_err("Invalid tag %x in flat device tree!\n", tag); - return -EINVAL; - } - depth++; - pathp = (char *)p; - p = ALIGN(p + strlen(pathp) + 1, 4); - if ((*pathp) == '/') { - char *lp, *np; - for (lp = NULL, np = pathp; *np; np++) - if ((*np) == '/') - lp = np+1; - if (lp != NULL) - pathp = lp; - } - rc = it(p, pathp, depth, data); - if (rc != 0) - break; - } while (1); - - return rc; -} - -/** - * of_get_flat_dt_root - find the root node in the flat blob - */ -unsigned long __init of_get_flat_dt_root(void) -{ - unsigned long p = ((unsigned long)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_struct); - - while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) - p += 4; - BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); - p += 4; - return ALIGN(p + strlen((char *)p) + 1, 4); -} - -/** - * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr - * - * This function can be used within scan_flattened_dt callback to get - * access to properties - */ -void *__init of_get_flat_dt_prop(unsigned long node, const char *name, - unsigned long *size) -{ - return of_fdt_get_property(initial_boot_params, node, name, size); -} - -/** - * of_flat_dt_is_compatible - Return true if given node has compat in compatible list - * @node: node to test - * @compat: compatible string to compare with compatible list. - */ -int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) -{ - return of_fdt_is_compatible(initial_boot_params, node, compat); -} - static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size, unsigned long align) { @@ -421,6 +312,115 @@ unsigned long unflatten_dt_node(struct boot_param_header *blob, return mem; } +/* Everything below here references initial_boot_params directly. */ +int __initdata dt_root_addr_cells; +int __initdata dt_root_size_cells; + +struct boot_param_header *initial_boot_params; + +#ifdef CONFIG_OF_EARLY_FLATTREE + +/** + * of_scan_flat_dt - scan flattened tree blob and call callback on each. + * @it: callback function + * @data: context data pointer + * + * This function is used to scan the flattened device-tree, it is + * used to extract the memory information at boot before we can + * unflatten the tree + */ +int __init of_scan_flat_dt(int (*it)(unsigned long node, + const char *uname, int depth, + void *data), + void *data) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + be32_to_cpu(initial_boot_params->off_dt_struct); + int rc = 0; + int depth = -1; + + do { + u32 tag = be32_to_cpup((__be32 *)p); + char *pathp; + + p += 4; + if (tag == OF_DT_END_NODE) { + depth--; + continue; + } + if (tag == OF_DT_NOP) + continue; + if (tag == OF_DT_END) + break; + if (tag == OF_DT_PROP) { + u32 sz = be32_to_cpup((__be32 *)p); + p += 8; + if (be32_to_cpu(initial_boot_params->version) < 0x10) + p = ALIGN(p, sz >= 8 ? 8 : 4); + p += sz; + p = ALIGN(p, 4); + continue; + } + if (tag != OF_DT_BEGIN_NODE) { + pr_err("Invalid tag %x in flat device tree!\n", tag); + return -EINVAL; + } + depth++; + pathp = (char *)p; + p = ALIGN(p + strlen(pathp) + 1, 4); + if ((*pathp) == '/') { + char *lp, *np; + for (lp = NULL, np = pathp; *np; np++) + if ((*np) == '/') + lp = np+1; + if (lp != NULL) + pathp = lp; + } + rc = it(p, pathp, depth, data); + if (rc != 0) + break; + } while (1); + + return rc; +} + +/** + * of_get_flat_dt_root - find the root node in the flat blob + */ +unsigned long __init of_get_flat_dt_root(void) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + be32_to_cpu(initial_boot_params->off_dt_struct); + + while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) + p += 4; + BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); + p += 4; + return ALIGN(p + strlen((char *)p) + 1, 4); +} + +/** + * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr + * + * This function can be used within scan_flattened_dt callback to get + * access to properties + */ +void *__init of_get_flat_dt_prop(unsigned long node, const char *name, + unsigned long *size) +{ + return of_fdt_get_property(initial_boot_params, node, name, size); +} + +/** + * of_flat_dt_is_compatible - Return true if given node has compat in compatible list + * @node: node to test + * @compat: compatible string to compare with compatible list. + */ +int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) +{ + return of_fdt_is_compatible(initial_boot_params, node, compat); +} + #ifdef CONFIG_BLK_DEV_INITRD /** * early_init_dt_check_for_initrd - Decode initrd location from flat tree -- cgit v1.2.3 From fe14042358fac0673d4b6362a73796fd64379938 Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Thu, 18 Nov 2010 15:55:02 -0800 Subject: of/flattree: Refactor unflatten_device_tree and add fdt_unflatten_tree unflatten_device_tree has two dependencies on things that happen during boot time. Firstly, it references the initial device tree directly. Secondly, it allocates memory using the early boot allocator. This patch factors out these dependencies and uses the new __unflatten_device_tree function to implement a driver-visible fdt_unflatten_tree function, which can be used to unflatten a blob after boot time. V2: - remove extra __va() call - make dt_alloc functions return void *. This doesn't fix the general strangeness in this code that constantly casts back and forth between unsigned long and __be32 * Signed-off-by: Stephen Neuendorffer Signed-off-by: Grant Likely --- drivers/of/fdt.c | 149 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 51 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 71edc9cecd62..8a90ee42071a 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -11,10 +11,12 @@ #include #include +#include #include #include #include #include +#include #ifdef CONFIG_PPC #include @@ -312,6 +314,94 @@ unsigned long unflatten_dt_node(struct boot_param_header *blob, return mem; } +/** + * __unflatten_device_tree - create tree of device_nodes from flat blob + * + * unflattens a device-tree, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used. + * @blob: The blob to expand + * @mynodes: The device_node tree created by the call + * @dt_alloc: An allocator that provides a virtual address to memory + * for the resulting tree + */ +void __unflatten_device_tree(struct boot_param_header *blob, + struct device_node **mynodes, + void * (*dt_alloc)(u64 size, u64 align)) +{ + unsigned long start, mem, size; + struct device_node **allnextp = mynodes; + + pr_debug(" -> unflatten_device_tree()\n"); + + if (!blob) { + pr_debug("No device tree pointer\n"); + return; + } + + pr_debug("Unflattening device tree:\n"); + pr_debug("magic: %08x\n", be32_to_cpu(blob->magic)); + pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize)); + pr_debug("version: %08x\n", be32_to_cpu(blob->version)); + + if (be32_to_cpu(blob->magic) != OF_DT_HEADER) { + pr_err("Invalid device tree blob header\n"); + return; + } + + /* First pass, scan for size */ + start = ((unsigned long)blob) + + be32_to_cpu(blob->off_dt_struct); + size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0); + size = (size | 3) + 1; + + pr_debug(" size is %lx, allocating...\n", size); + + /* Allocate memory for the expanded device tree */ + mem = (unsigned long) + dt_alloc(size + 4, __alignof__(struct device_node)); + + ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); + + pr_debug(" unflattening %lx...\n", mem); + + /* Second pass, do actual unflattening */ + start = ((unsigned long)blob) + + be32_to_cpu(blob->off_dt_struct); + unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); + if (be32_to_cpup((__be32 *)start) != OF_DT_END) + pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); + if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) + pr_warning("End of tree marker overwritten: %08x\n", + be32_to_cpu(((__be32 *)mem)[size / 4])); + *allnextp = NULL; + + pr_debug(" <- unflatten_device_tree()\n"); +} + +static void *kernel_tree_alloc(u64 size, u64 align) +{ + return kzalloc(size, GFP_KERNEL); +} + +/** + * of_fdt_unflatten_tree - create tree of device_nodes from flat blob + * + * unflattens the device-tree passed by the firmware, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used. + */ +void of_fdt_unflatten_tree(unsigned long *blob, + struct device_node **mynodes) +{ + struct boot_param_header *device_tree = + (struct boot_param_header *)blob; + __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc); +} +EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); + /* Everything below here references initial_boot_params directly. */ int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; @@ -569,6 +659,12 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, return 1; } +static void *__init early_device_tree_alloc(u64 size, u64 align) +{ + unsigned long mem = early_init_dt_alloc_memory_arch(size, align); + return __va(mem); +} + /** * unflatten_device_tree - create tree of device_nodes from flat blob * @@ -579,62 +675,13 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, */ void __init unflatten_device_tree(void) { - unsigned long start, mem, size; - struct device_node **allnextp = &allnodes; - - pr_debug(" -> unflatten_device_tree()\n"); - - if (!initial_boot_params) { - pr_debug("No device tree pointer\n"); - return; - } - - pr_debug("Unflattening device tree:\n"); - pr_debug("magic: %08x\n", be32_to_cpu(initial_boot_params->magic)); - pr_debug("size: %08x\n", be32_to_cpu(initial_boot_params->totalsize)); - pr_debug("version: %08x\n", be32_to_cpu(initial_boot_params->version)); - - if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) { - pr_err("Invalid device tree blob header\n"); - return; - } - - /* First pass, scan for size */ - start = ((unsigned long)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_struct); - size = unflatten_dt_node(initial_boot_params, 0, &start, - NULL, NULL, 0); - size = (size | 3) + 1; - - pr_debug(" size is %lx, allocating...\n", size); - - /* Allocate memory for the expanded device tree */ - mem = early_init_dt_alloc_memory_arch(size + 4, - __alignof__(struct device_node)); - mem = (unsigned long) __va(mem); - - ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); - - pr_debug(" unflattening %lx...\n", mem); - - /* Second pass, do actual unflattening */ - start = ((unsigned long)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_struct); - unflatten_dt_node(initial_boot_params, mem, &start, - NULL, &allnextp, 0); - if (be32_to_cpup((__be32 *)start) != OF_DT_END) - pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); - if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) - pr_warning("End of tree marker overwritten: %08x\n", - be32_to_cpu(((__be32 *)mem)[size / 4])); - *allnextp = NULL; + __unflatten_device_tree(initial_boot_params, &allnodes, + early_device_tree_alloc); /* Get pointer to OF "/chosen" node for use everywhere */ of_chosen = of_find_node_by_path("/chosen"); if (of_chosen == NULL) of_chosen = of_find_node_by_path("/chosen@0"); - - pr_debug(" <- unflatten_device_tree()\n"); } #endif /* CONFIG_OF_EARLY_FLATTREE */ -- cgit v1.2.3 From a4f740cf33f7f6c164bbde3c0cdbcc77b0c4997c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 30 Oct 2010 11:49:09 -0400 Subject: of/flattree: Add of_flat_dt_match() helper function This patch adds of_flat_dt_match() which tests a node for compatibility with a list of values and converts the relevant powerpc platform code to use it. This approach simplifies the board support code a bit. Signed-off-by: Grant Likely Reviewed-by: Stephen Neuendorffer --- drivers/of/fdt.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 8a90ee42071a..c787c3d95c60 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -78,19 +78,23 @@ void *of_fdt_get_property(struct boot_param_header *blob, * @blob: A device tree blob * @node: node to test * @compat: compatible string to compare with compatible list. + * + * On match, returns a non-zero value with smaller values returned for more + * specific compatible values. */ int of_fdt_is_compatible(struct boot_param_header *blob, unsigned long node, const char *compat) { const char *cp; - unsigned long cplen, l; + unsigned long cplen, l, score = 0; cp = of_fdt_get_property(blob, node, "compatible", &cplen); if (cp == NULL) return 0; while (cplen > 0) { + score++; if (of_compat_cmp(cp, compat, strlen(compat)) == 0) - return 1; + return score; l = strlen(cp) + 1; cp += l; cplen -= l; @@ -99,6 +103,27 @@ int of_fdt_is_compatible(struct boot_param_header *blob, return 0; } +/** + * of_fdt_match - Return true if node matches a list of compatible values + */ +int of_fdt_match(struct boot_param_header *blob, unsigned long node, + const char **compat) +{ + unsigned int tmp, score = 0; + + if (!compat) + return 0; + + while (*compat) { + tmp = of_fdt_is_compatible(blob, node, *compat); + if (tmp && (score == 0 || (tmp < score))) + score = tmp; + compat++; + } + + return score; +} + static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size, unsigned long align) { @@ -511,6 +536,14 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) return of_fdt_is_compatible(initial_boot_params, node, compat); } +/** + * of_flat_dt_match - Return true if node matches a list of compatible values + */ +int __init of_flat_dt_match(unsigned long node, const char **compat) +{ + return of_fdt_match(initial_boot_params, node, compat); +} + #ifdef CONFIG_BLK_DEV_INITRD /** * early_init_dt_check_for_initrd - Decode initrd location from flat tree -- cgit v1.2.3 From cd1e65044d4473cca9a01bae7b7938f065044a4b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 3 Jan 2011 15:51:11 -0700 Subject: of/device: Don't register disabled devices Device nodes with the property status="disabled" are not usable and so don't register them when parsing the device tree for devices. Signed-off-by: Grant Likely Cc: Hollis Blanchard Cc: Deepak Saxena Cc: Scott Wood , Cc: David Gibson Cc: Benjamin Herrenschmidt --- drivers/of/platform.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 5b4a07f1220e..c01cd1ac7617 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -633,6 +633,9 @@ EXPORT_SYMBOL(of_device_alloc); * @np: pointer to node to create device for * @bus_id: name to assign device * @parent: Linux device model parent device. + * + * Returns pointer to created platform device, or NULL if a device was not + * registered. Unavailable devices will not get registered. */ struct platform_device *of_platform_device_create(struct device_node *np, const char *bus_id, @@ -640,6 +643,9 @@ struct platform_device *of_platform_device_create(struct device_node *np, { struct platform_device *dev; + if (!of_device_is_available(np)) + return NULL; + dev = of_device_alloc(np, bus_id, parent); if (!dev) return NULL; @@ -683,8 +689,9 @@ static int of_platform_bus_create(const struct device_node *bus, pr_debug(" create child: %s\n", child->full_name); dev = of_platform_device_create(child, NULL, parent); if (dev == NULL) - rc = -ENOMEM; - else if (!of_match_node(matches, child)) + continue; + + if (!of_match_node(matches, child)) continue; if (rc == 0) { pr_debug(" and sub busses\n"); @@ -733,10 +740,9 @@ int of_platform_bus_probe(struct device_node *root, if (of_match_node(matches, root)) { pr_debug(" root match, create all sub devices\n"); dev = of_platform_device_create(root, NULL, parent); - if (dev == NULL) { - rc = -ENOMEM; + if (dev == NULL) goto bail; - } + pr_debug(" create all sub busses\n"); rc = of_platform_bus_create(root, matches, &dev->dev); goto bail; @@ -748,9 +754,9 @@ int of_platform_bus_probe(struct device_node *root, pr_debug(" match: %s\n", child->full_name); dev = of_platform_device_create(child, NULL, parent); if (dev == NULL) - rc = -ENOMEM; - else - rc = of_platform_bus_create(child, matches, &dev->dev); + continue; + + rc = of_platform_bus_create(child, matches, &dev->dev); if (rc) { of_node_put(child); break; -- cgit v1.2.3