diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-21 00:51:34 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-21 00:51:34 +0300 |
commit | e7f44b65b532040ac90b73b60ea0b629742ced33 (patch) | |
tree | 1dec69d411543c5c8ee1b61311db4470070745f0 /drivers | |
parent | 76b584d3125a1f7d8b64e9c522a4555bc2844bde (diff) | |
parent | f2c27767af0a91cbdc3d832231f953110473e853 (diff) | |
download | linux-e7f44b65b532040ac90b73b60ea0b629742ced33.tar.xz |
Merge tag 'devicetree-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
Pull devicetree updates from Rob Herring:
- Rewrite of the unflattening code to avoid recursion and lessen the
stack usage.
- Rewrite of the phandle args parsing code to get rid of the fixed args
size. This is needed for IOMMU code.
- Sync to latest dtc which adds more dts style checking. These
warnings are enabled with "W=1" compiles.
- Tegra documentation updates related to the above warnings.
- A bunch of spelling and other doc fixes.
- Various vendor prefix additions.
* tag 'devicetree-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (52 commits)
devicetree: Add Creative Technology vendor id
gpio: dt-bindings: add ibm,ppc4xx-gpio binding
of/unittest: Remove unnecessary module.h header inclusion
drivers/of: Fix build warning in populate_node()
drivers/of: Fix depth when unflattening devicetree
of: dynamic: changeset prop-update revert fix
drivers/of: Export of_detach_node()
drivers/of: Return allocated memory from of_fdt_unflatten_tree()
drivers/of: Specify parent node in of_fdt_unflatten_tree()
drivers/of: Rename unflatten_dt_node()
drivers/of: Avoid recursively calling unflatten_dt_node()
drivers/of: Split unflatten_dt_node()
of: include errno.h in of_graph.h
of: document refcount incrementation of of_get_cpu_node()
Documentation: dt: soc: fix spelling mistakes
Documentation: dt: power: fix spelling mistake
Documentation: dt: pinctrl: fix spelling mistake
Documentation: dt: opp: fix spelling mistake
Documentation: dt: net: fix spelling mistakes
Documentation: dt: mtd: fix spelling mistake
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 2 | ||||
-rw-r--r-- | drivers/iommu/arm-smmu.c | 38 | ||||
-rw-r--r-- | drivers/of/base.c | 209 | ||||
-rw-r--r-- | drivers/of/dynamic.c | 6 | ||||
-rw-r--r-- | drivers/of/fdt.c | 382 | ||||
-rw-r--r-- | drivers/of/unittest.c | 3 |
6 files changed, 411 insertions, 229 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c index 106679bca6cb..f9c79dabce20 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c @@ -157,7 +157,7 @@ struct device_node * __init tilcdc_get_overlay(struct kfree_table *kft) if (!overlay_data || kfree_table_add(kft, overlay_data)) return NULL; - of_fdt_unflatten_tree(overlay_data, &overlay); + of_fdt_unflatten_tree(overlay_data, NULL, &overlay); if (!overlay) { pr_warn("%s: Unfattening overlay tree failed\n", __func__); return NULL; diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 0360919a5737..e206ce7a4e4b 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -50,7 +50,7 @@ #include "io-pgtable.h" /* Maximum number of stream IDs assigned to a single device */ -#define MAX_MASTER_STREAMIDS MAX_PHANDLE_ARGS +#define MAX_MASTER_STREAMIDS 128 /* Maximum number of context banks per SMMU */ #define ARM_SMMU_MAX_CBS 128 @@ -397,6 +397,12 @@ struct arm_smmu_domain { struct iommu_domain domain; }; +struct arm_smmu_phandle_args { + struct device_node *np; + int args_count; + uint32_t args[MAX_MASTER_STREAMIDS]; +}; + static DEFINE_SPINLOCK(arm_smmu_devices_lock); static LIST_HEAD(arm_smmu_devices); @@ -506,7 +512,7 @@ static int insert_smmu_master(struct arm_smmu_device *smmu, static int register_smmu_master(struct arm_smmu_device *smmu, struct device *dev, - struct of_phandle_args *masterspec) + struct arm_smmu_phandle_args *masterspec) { int i; struct arm_smmu_master *master; @@ -1875,7 +1881,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) struct arm_smmu_device *smmu; struct device *dev = &pdev->dev; struct rb_node *node; - struct of_phandle_args masterspec; + struct of_phandle_iterator it; + struct arm_smmu_phandle_args *masterspec; int num_irqs, i, err; smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL); @@ -1938,20 +1945,35 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) i = 0; smmu->masters = RB_ROOT; - while (!of_parse_phandle_with_args(dev->of_node, "mmu-masters", - "#stream-id-cells", i, - &masterspec)) { - err = register_smmu_master(smmu, dev, &masterspec); + + err = -ENOMEM; + /* No need to zero the memory for masterspec */ + masterspec = kmalloc(sizeof(*masterspec), GFP_KERNEL); + if (!masterspec) + goto out_put_masters; + + of_for_each_phandle(&it, err, dev->of_node, + "mmu-masters", "#stream-id-cells", 0) { + int count = of_phandle_iterator_args(&it, masterspec->args, + MAX_MASTER_STREAMIDS); + masterspec->np = of_node_get(it.node); + masterspec->args_count = count; + + err = register_smmu_master(smmu, dev, masterspec); if (err) { dev_err(dev, "failed to add master %s\n", - masterspec.np->name); + masterspec->np->name); + kfree(masterspec); goto out_put_masters; } i++; } + dev_notice(dev, "registered %d master devices\n", i); + kfree(masterspec); + parse_driver_options(smmu); if (smmu->version == ARM_SMMU_V2 && diff --git a/drivers/of/base.c b/drivers/of/base.c index 64018ebcc861..ebf84e3b56d5 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -394,7 +394,8 @@ bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun, * before booting secondary cores. This function uses arch_match_cpu_phys_id * which can be overridden by architecture specific implementation. * - * Returns a node pointer for the logical cpu if found, else NULL. + * Returns a node pointer for the logical cpu with refcount incremented, use + * of_node_put() on it when done. Returns NULL if not found. */ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) { @@ -1440,106 +1441,155 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) printk("\n"); } -static int __of_parse_phandle_with_args(const struct device_node *np, - const char *list_name, - const char *cells_name, - int cell_count, int index, - struct of_phandle_args *out_args) +int of_phandle_iterator_init(struct of_phandle_iterator *it, + const struct device_node *np, + const char *list_name, + const char *cells_name, + int cell_count) { - const __be32 *list, *list_end; - int rc = 0, size, cur_index = 0; - uint32_t count = 0; - struct device_node *node = NULL; - phandle phandle; + const __be32 *list; + int size; + + memset(it, 0, sizeof(*it)); - /* Retrieve the phandle list property */ list = of_get_property(np, list_name, &size); if (!list) return -ENOENT; - list_end = list + size / sizeof(*list); - /* Loop over the phandles until all the requested entry is found */ - while (list < list_end) { - rc = -EINVAL; - count = 0; + it->cells_name = cells_name; + it->cell_count = cell_count; + it->parent = np; + it->list_end = list + size / sizeof(*list); + it->phandle_end = list; + it->cur = list; + + return 0; +} + +int of_phandle_iterator_next(struct of_phandle_iterator *it) +{ + uint32_t count = 0; + + if (it->node) { + of_node_put(it->node); + it->node = NULL; + } + + if (!it->cur || it->phandle_end >= it->list_end) + return -ENOENT; + + it->cur = it->phandle_end; + + /* If phandle is 0, then it is an empty entry with no arguments. */ + it->phandle = be32_to_cpup(it->cur++); + + if (it->phandle) { /* - * If phandle is 0, then it is an empty entry with no - * arguments. Skip forward to the next entry. + * Find the provider node and parse the #*-cells property to + * determine the argument length. */ - phandle = be32_to_cpup(list++); - if (phandle) { - /* - * Find the provider node and parse the #*-cells - * property to determine the argument length. - * - * This is not needed if the cell count is hard-coded - * (i.e. cells_name not set, but cell_count is set), - * except when we're going to return the found node - * below. - */ - if (cells_name || cur_index == index) { - node = of_find_node_by_phandle(phandle); - if (!node) { - pr_err("%s: could not find phandle\n", - np->full_name); - goto err; - } - } + it->node = of_find_node_by_phandle(it->phandle); - if (cells_name) { - if (of_property_read_u32(node, cells_name, - &count)) { - pr_err("%s: could not get %s for %s\n", - np->full_name, cells_name, - node->full_name); - goto err; - } - } else { - count = cell_count; + if (it->cells_name) { + if (!it->node) { + pr_err("%s: could not find phandle\n", + it->parent->full_name); + goto err; } - /* - * Make sure that the arguments actually fit in the - * remaining property data length - */ - if (list + count > list_end) { - pr_err("%s: arguments longer than property\n", - np->full_name); + if (of_property_read_u32(it->node, it->cells_name, + &count)) { + pr_err("%s: could not get %s for %s\n", + it->parent->full_name, + it->cells_name, + it->node->full_name); goto err; } + } else { + count = it->cell_count; } /* - * All of the error cases above bail out of the loop, so at + * Make sure that the arguments actually fit in the remaining + * property data length + */ + if (it->cur + count > it->list_end) { + pr_err("%s: arguments longer than property\n", + it->parent->full_name); + goto err; + } + } + + it->phandle_end = it->cur + count; + it->cur_count = count; + + return 0; + +err: + if (it->node) { + of_node_put(it->node); + it->node = NULL; + } + + return -EINVAL; +} + +int of_phandle_iterator_args(struct of_phandle_iterator *it, + uint32_t *args, + int size) +{ + int i, count; + + count = it->cur_count; + + if (WARN_ON(size < count)) + count = size; + + for (i = 0; i < count; i++) + args[i] = be32_to_cpup(it->cur++); + + return count; +} + +static int __of_parse_phandle_with_args(const struct device_node *np, + const char *list_name, + const char *cells_name, + int cell_count, int index, + struct of_phandle_args *out_args) +{ + struct of_phandle_iterator it; + int rc, cur_index = 0; + + /* Loop over the phandles until all the requested entry is found */ + of_for_each_phandle(&it, rc, np, list_name, cells_name, cell_count) { + /* + * All of the error cases bail out of the loop, so at * this point, the parsing is successful. If the requested * index matches, then fill the out_args structure and return, * or return -ENOENT for an empty entry. */ rc = -ENOENT; if (cur_index == index) { - if (!phandle) + if (!it.phandle) goto err; if (out_args) { - int i; - if (WARN_ON(count > MAX_PHANDLE_ARGS)) - count = MAX_PHANDLE_ARGS; - out_args->np = node; - out_args->args_count = count; - for (i = 0; i < count; i++) - out_args->args[i] = be32_to_cpup(list++); + int c; + + c = of_phandle_iterator_args(&it, + out_args->args, + MAX_PHANDLE_ARGS); + out_args->np = it.node; + out_args->args_count = c; } else { - of_node_put(node); + of_node_put(it.node); } /* Found it! return success */ return 0; } - of_node_put(node); - node = NULL; - list += count; cur_index++; } @@ -1547,12 +1597,11 @@ static int __of_parse_phandle_with_args(const struct device_node *np, * Unlock node before returning result; will be one of: * -ENOENT : index is for empty phandle * -EINVAL : parsing error on data - * [1..n] : Number of phandle (count mode; when index = -1) */ - rc = index < 0 ? cur_index : -ENOENT; + err: - if (node) - of_node_put(node); + if (it.node) + of_node_put(it.node); return rc; } @@ -1684,8 +1733,20 @@ EXPORT_SYMBOL(of_parse_phandle_with_fixed_args); int of_count_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name) { - return __of_parse_phandle_with_args(np, list_name, cells_name, 0, -1, - NULL); + struct of_phandle_iterator it; + int rc, cur_index = 0; + + rc = of_phandle_iterator_init(&it, np, list_name, cells_name, 0); + if (rc) + return rc; + + while ((rc = of_phandle_iterator_next(&it)) == 0) + cur_index += 1; + + if (rc != -ENOENT) + return rc; + + return cur_index; } EXPORT_SYMBOL(of_count_phandle_with_args); diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index c647bd1b6903..3033fa3250dc 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -311,6 +311,7 @@ int of_detach_node(struct device_node *np) return rc; } +EXPORT_SYMBOL_GPL(of_detach_node); /** * of_node_release() - release a dynamically allocated node @@ -497,6 +498,11 @@ static void __of_changeset_entry_invert(struct of_changeset_entry *ce, case OF_RECONFIG_UPDATE_PROPERTY: rce->old_prop = ce->prop; rce->prop = ce->old_prop; + /* update was used but original property did not exist */ + if (!rce->prop) { + rce->action = OF_RECONFIG_REMOVE_PROPERTY; + rce->prop = ce->prop; + } break; } } diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 3349d2aa6634..14f2f8c7c260 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -161,39 +161,127 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size, return res; } -/** - * unflatten_dt_node - Alloc and populate a device_node from the flat tree - * @blob: The parent device tree blob - * @mem: Memory chunk to use for allocating device nodes and properties - * @poffset: pointer to node in flat tree - * @dad: Parent struct device_node - * @nodepp: The device_node tree created by the call - * @fpsize: Size of the node path up at the current depth. - * @dryrun: If true, do not allocate device nodes but still calculate needed - * memory size - */ -static void * unflatten_dt_node(const void *blob, - void *mem, - int *poffset, - struct device_node *dad, - struct device_node **nodepp, - unsigned long fpsize, +static void populate_properties(const void *blob, + int offset, + void **mem, + struct device_node *np, + const char *nodename, bool dryrun) { - const __be32 *p; + struct property *pp, **pprev = NULL; + int cur; + bool has_name = false; + + pprev = &np->properties; + for (cur = fdt_first_property_offset(blob, offset); + cur >= 0; + cur = fdt_next_property_offset(blob, cur)) { + const __be32 *val; + const char *pname; + u32 sz; + + val = fdt_getprop_by_offset(blob, cur, &pname, &sz); + if (!val) { + pr_warn("%s: Cannot locate property at 0x%x\n", + __func__, cur); + continue; + } + + if (!pname) { + pr_warn("%s: Cannot find property name at 0x%x\n", + __func__, cur); + continue; + } + + if (!strcmp(pname, "name")) + has_name = true; + + pp = unflatten_dt_alloc(mem, sizeof(struct property), + __alignof__(struct property)); + if (dryrun) + continue; + + /* We accept flattened tree phandles either in + * ePAPR-style "phandle" properties, or the + * legacy "linux,phandle" properties. If both + * appear and have different values, things + * will get weird. Don't do that. + */ + if (!strcmp(pname, "phandle") || + !strcmp(pname, "linux,phandle")) { + if (!np->phandle) + np->phandle = be32_to_cpup(val); + } + + /* And we process the "ibm,phandle" property + * used in pSeries dynamic device tree + * stuff + */ + if (!strcmp(pname, "ibm,phandle")) + np->phandle = be32_to_cpup(val); + + pp->name = (char *)pname; + pp->length = sz; + pp->value = (__be32 *)val; + *pprev = pp; + pprev = &pp->next; + } + + /* With version 0x10 we may not have the name property, + * recreate it here from the unit name if absent + */ + if (!has_name) { + const char *p = nodename, *ps = p, *pa = NULL; + int len; + + while (*p) { + if ((*p) == '@') + pa = p; + else if ((*p) == '/') + ps = p + 1; + p++; + } + + if (pa < ps) + pa = p; + len = (pa - ps) + 1; + pp = unflatten_dt_alloc(mem, sizeof(struct property) + len, + __alignof__(struct property)); + if (!dryrun) { + pp->name = "name"; + pp->length = len; + pp->value = pp + 1; + *pprev = pp; + pprev = &pp->next; + memcpy(pp->value, ps, len - 1); + ((char *)pp->value)[len - 1] = 0; + pr_debug("fixed up name for %s -> %s\n", + nodename, (char *)pp->value); + } + } + + if (!dryrun) + *pprev = NULL; +} + +static unsigned int populate_node(const void *blob, + int offset, + void **mem, + struct device_node *dad, + unsigned int fpsize, + struct device_node **pnp, + bool dryrun) +{ struct device_node *np; - struct property *pp, **prev_pp = NULL; const char *pathp; unsigned int l, allocl; - static int depth; - int old_depth; - int offset; - int has_name = 0; int new_format = 0; - pathp = fdt_get_name(blob, *poffset, &l); - if (!pathp) - return mem; + pathp = fdt_get_name(blob, offset, &l); + if (!pathp) { + *pnp = NULL; + return 0; + } allocl = ++l; @@ -223,7 +311,7 @@ static void * unflatten_dt_node(const void *blob, } } - np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, + np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl, __alignof__(struct device_node)); if (!dryrun) { char *fn; @@ -246,89 +334,15 @@ static void * unflatten_dt_node(const void *blob, } memcpy(fn, pathp, l); - prev_pp = &np->properties; if (dad != NULL) { np->parent = dad; np->sibling = dad->child; dad->child = np; } } - /* process properties */ - for (offset = fdt_first_property_offset(blob, *poffset); - (offset >= 0); - (offset = fdt_next_property_offset(blob, offset))) { - const char *pname; - u32 sz; - - if (!(p = fdt_getprop_by_offset(blob, offset, &pname, &sz))) { - offset = -FDT_ERR_INTERNAL; - break; - } - if (pname == NULL) { - pr_info("Can't find property name in list !\n"); - break; - } - if (strcmp(pname, "name") == 0) - has_name = 1; - pp = unflatten_dt_alloc(&mem, sizeof(struct property), - __alignof__(struct property)); - if (!dryrun) { - /* We accept flattened tree phandles either in - * ePAPR-style "phandle" properties, or the - * legacy "linux,phandle" properties. If both - * appear and have different values, things - * will get weird. Don't do that. */ - if ((strcmp(pname, "phandle") == 0) || - (strcmp(pname, "linux,phandle") == 0)) { - if (np->phandle == 0) - np->phandle = be32_to_cpup(p); - } - /* And we process the "ibm,phandle" property - * used in pSeries dynamic device tree - * stuff */ - if (strcmp(pname, "ibm,phandle") == 0) - np->phandle = be32_to_cpup(p); - pp->name = (char *)pname; - pp->length = sz; - pp->value = (__be32 *)p; - *prev_pp = pp; - prev_pp = &pp->next; - } - } - /* with version 0x10 we may not have the name property, recreate - * it here from the unit name if absent - */ - if (!has_name) { - const char *p1 = pathp, *ps = pathp, *pa = NULL; - int sz; - - while (*p1) { - if ((*p1) == '@') - pa = p1; - if ((*p1) == '/') - ps = p1 + 1; - p1++; - } - if (pa < ps) - pa = p1; - sz = (pa - ps) + 1; - pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, - __alignof__(struct property)); - if (!dryrun) { - pp->name = "name"; - pp->length = sz; - pp->value = pp + 1; - *prev_pp = pp; - prev_pp = &pp->next; - memcpy(pp->value, ps, sz - 1); - ((char *)pp->value)[sz - 1] = 0; - pr_debug("fixed up name for %s -> %s\n", pathp, - (char *)pp->value); - } - } + populate_properties(blob, offset, mem, np, pathp, dryrun); if (!dryrun) { - *prev_pp = NULL; np->name = of_get_property(np, "name", NULL); np->type = of_get_property(np, "device_type", NULL); @@ -338,36 +352,94 @@ static void * unflatten_dt_node(const void *blob, np->type = "<NULL>"; } - old_depth = depth; - *poffset = fdt_next_node(blob, *poffset, &depth); - if (depth < 0) - depth = 0; - while (*poffset > 0 && depth > old_depth) - mem = unflatten_dt_node(blob, mem, poffset, np, NULL, - fpsize, dryrun); + *pnp = np; + return fpsize; +} + +static void reverse_nodes(struct device_node *parent) +{ + struct device_node *child, *next; + + /* In-depth first */ + child = parent->child; + while (child) { + reverse_nodes(child); + + child = child->sibling; + } + + /* Reverse the nodes in the child list */ + child = parent->child; + parent->child = NULL; + while (child) { + next = child->sibling; + + child->sibling = parent->child; + parent->child = child; + child = next; + } +} + +/** + * unflatten_dt_nodes - Alloc and populate a device_node from the flat tree + * @blob: The parent device tree blob + * @mem: Memory chunk to use for allocating device nodes and properties + * @dad: Parent struct device_node + * @nodepp: The device_node tree created by the call + * + * It returns the size of unflattened device tree or error code + */ +static int unflatten_dt_nodes(const void *blob, + void *mem, + struct device_node *dad, + struct device_node **nodepp) +{ + struct device_node *root; + int offset = 0, depth = 0; +#define FDT_MAX_DEPTH 64 + unsigned int fpsizes[FDT_MAX_DEPTH]; + struct device_node *nps[FDT_MAX_DEPTH]; + void *base = mem; + bool dryrun = !base; - if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) - pr_err("unflatten: error %d processing FDT\n", *poffset); + if (nodepp) + *nodepp = NULL; + + root = dad; + fpsizes[depth] = dad ? strlen(of_node_full_name(dad)) : 0; + nps[depth] = dad; + for (offset = 0; + offset >= 0 && depth >= 0; + offset = fdt_next_node(blob, offset, &depth)) { + if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH)) + continue; + + fpsizes[depth+1] = populate_node(blob, offset, &mem, + nps[depth], + fpsizes[depth], + &nps[depth+1], dryrun); + if (!fpsizes[depth+1]) + return mem - base; + + if (!dryrun && nodepp && !*nodepp) + *nodepp = nps[depth+1]; + if (!dryrun && !root) + root = nps[depth+1]; + } + + if (offset < 0 && offset != -FDT_ERR_NOTFOUND) { + pr_err("%s: Error %d processing FDT\n", __func__, offset); + return -EINVAL; + } /* * Reverse the child list. Some drivers assumes node order matches .dts * node order */ - if (!dryrun && np->child) { - struct device_node *child = np->child; - np->child = NULL; - while (child) { - struct device_node *next = child->sibling; - child->sibling = np->child; - np->child = child; - child = next; - } - } - - if (nodepp) - *nodepp = np; + if (!dryrun) + reverse_nodes(root); - return mem; + return mem - base; } /** @@ -378,23 +450,27 @@ static void * unflatten_dt_node(const void *blob, * pointers of the nodes so the normal device-tree walking functions * can be used. * @blob: The blob to expand + * @dad: Parent device node * @mynodes: The device_node tree created by the call * @dt_alloc: An allocator that provides a virtual address to memory * for the resulting tree + * + * Returns NULL on failure or the memory chunk containing the unflattened + * device tree on success. */ -static void __unflatten_device_tree(const void *blob, - struct device_node **mynodes, - void * (*dt_alloc)(u64 size, u64 align)) +static void *__unflatten_device_tree(const void *blob, + struct device_node *dad, + struct device_node **mynodes, + void *(*dt_alloc)(u64 size, u64 align)) { - unsigned long size; - int start; + int size; void *mem; pr_debug(" -> unflatten_device_tree()\n"); if (!blob) { pr_debug("No device tree pointer\n"); - return; + return NULL; } pr_debug("Unflattening device tree:\n"); @@ -404,15 +480,16 @@ static void __unflatten_device_tree(const void *blob, if (fdt_check_header(blob)) { pr_err("Invalid device tree blob header\n"); - return; + return NULL; } /* First pass, scan for size */ - start = 0; - size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0, true); - size = ALIGN(size, 4); + size = unflatten_dt_nodes(blob, NULL, dad, NULL); + if (size < 0) + return NULL; - pr_debug(" size is %lx, allocating...\n", size); + size = ALIGN(size, 4); + pr_debug(" size is %d, allocating...\n", size); /* Allocate memory for the expanded device tree */ mem = dt_alloc(size + 4, __alignof__(struct device_node)); @@ -423,13 +500,13 @@ static void __unflatten_device_tree(const void *blob, pr_debug(" unflattening %p...\n", mem); /* Second pass, do actual unflattening */ - start = 0; - unflatten_dt_node(blob, mem, &start, NULL, mynodes, 0, false); + unflatten_dt_nodes(blob, mem, dad, mynodes); if (be32_to_cpup(mem + size) != 0xdeadbeef) pr_warning("End of tree marker overwritten: %08x\n", be32_to_cpup(mem + size)); pr_debug(" <- unflatten_device_tree()\n"); + return mem; } static void *kernel_tree_alloc(u64 size, u64 align) @@ -441,18 +518,29 @@ static DEFINE_MUTEX(of_fdt_unflatten_mutex); /** * of_fdt_unflatten_tree - create tree of device_nodes from flat blob + * @blob: Flat device tree blob + * @dad: Parent device node + * @mynodes: The device tree created by the call * * 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. + * + * Returns NULL on failure or the memory chunk containing the unflattened + * device tree on success. */ -void of_fdt_unflatten_tree(const unsigned long *blob, - struct device_node **mynodes) +void *of_fdt_unflatten_tree(const unsigned long *blob, + struct device_node *dad, + struct device_node **mynodes) { + void *mem; + mutex_lock(&of_fdt_unflatten_mutex); - __unflatten_device_tree(blob, mynodes, &kernel_tree_alloc); + mem = __unflatten_device_tree(blob, dad, mynodes, &kernel_tree_alloc); mutex_unlock(&of_fdt_unflatten_mutex); + + return mem; } EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); @@ -969,10 +1057,16 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, * is set in which case we override whatever was found earlier. */ #ifdef CONFIG_CMDLINE -#ifndef CONFIG_CMDLINE_FORCE +#if defined(CONFIG_CMDLINE_EXTEND) + strlcat(data, " ", COMMAND_LINE_SIZE); + strlcat(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#elif defined(CONFIG_CMDLINE_FORCE) + strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#else + /* No arguments from boot loader, use kernel's cmdl*/ if (!((char *)data)[0]) -#endif strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#endif #endif /* CONFIG_CMDLINE */ pr_debug("Command line is: %s\n", (char*)data); @@ -1118,7 +1212,7 @@ bool __init early_init_dt_scan(void *params) */ void __init unflatten_device_tree(void) { - __unflatten_device_tree(initial_boot_params, &of_root, + __unflatten_device_tree(initial_boot_params, NULL, &of_root, early_init_dt_alloc_memory_arch); /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index c1ebbfb79453..f34ed9310323 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -8,7 +8,6 @@ #include <linux/err.h> #include <linux/errno.h> #include <linux/hashtable.h> -#include <linux/module.h> #include <linux/of.h> #include <linux/of_fdt.h> #include <linux/of_irq.h> @@ -921,7 +920,7 @@ static int __init unittest_data_add(void) "not running tests\n", __func__); return -ENOMEM; } - of_fdt_unflatten_tree(unittest_data, &unittest_data_node); + of_fdt_unflatten_tree(unittest_data, NULL, &unittest_data_node); if (!unittest_data_node) { pr_warn("%s: No tree to attach; not running tests\n", __func__); return -ENODATA; |