diff options
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/Kconfig | 8 | ||||
-rw-r--r-- | drivers/of/Makefile | 1 | ||||
-rw-r--r-- | drivers/of/address.c | 54 | ||||
-rw-r--r-- | drivers/of/fdt.c | 430 | ||||
-rw-r--r-- | drivers/of/of_mdio.c | 26 | ||||
-rw-r--r-- | drivers/of/of_net.c | 48 | ||||
-rw-r--r-- | drivers/of/platform.c | 22 |
7 files changed, 388 insertions, 201 deletions
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index aa675ebd8eb3..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 @@ -49,6 +53,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/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; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index c1360e02f921..c787c3d95c60 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -11,10 +11,12 @@ #include <linux/kernel.h> #include <linux/initrd.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/of_fdt.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/slab.h> #ifdef CONFIG_PPC #include <asm/machdep.h> @@ -22,104 +24,19 @@ #include <asm/page.h> -int __initdata dt_root_addr_cells; -int __initdata dt_root_size_cells; - -struct boot_param_header *initial_boot_params; - -char *find_flat_dt_string(u32 offset) +char *of_fdt_get_string(struct boot_param_header *blob, 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 - * @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; + return ((char *)blob) + + be32_to_cpu(blob->off_dt_strings) + offset; } /** - * of_get_flat_dt_root - find the root node in the flat blob + * of_fdt_get_property - Given a node in the given flat blob, return + * the property ptr */ -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) +void *of_fdt_get_property(struct boot_param_header *blob, + unsigned long node, const char *name, + unsigned long *size) { unsigned long p = node; @@ -137,10 +54,10 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, 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); - nstr = find_flat_dt_string(noff); + nstr = of_fdt_get_string(blob, noff); if (nstr == NULL) { pr_warning("Can't find property index name !\n"); return NULL; @@ -156,21 +73,28 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, } /** - * of_flat_dt_is_compatible - Return true if given node has compat in compatible list + * 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. + * + * On match, returns a non-zero value with smaller values returned for more + * specific compatible values. */ -int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) +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_get_flat_dt_prop(node, "compatible", &cplen); + 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; @@ -179,7 +103,28 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) return 0; } -static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, +/** + * 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) { void *res; @@ -193,16 +138,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; @@ -298,10 +245,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 = find_flat_dt_string(noff); + pname = of_fdt_get_string(blob, noff); if (pname == NULL) { pr_info("Can't find property name in list !\n"); break; @@ -380,7 +327,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) { @@ -391,6 +339,211 @@ unsigned long __init unflatten_dt_node(unsigned long mem, 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; + +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); +} + +/** + * 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 @@ -539,6 +692,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 * @@ -549,58 +708,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(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(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 */ 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; 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 <linux/etherdevice.h> +#include <linux/kernel.h> +#include <linux/of_net.h> + +/** + * 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); 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; |