diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-06 06:03:42 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-06 06:03:42 +0200 |
commit | 9c2dd8405c0cc2288d6098df40c19569d17553e4 (patch) | |
tree | 08ffc47fb00b1a327db95de4b5339797afeb8f48 /drivers/of | |
parent | Merge branch 'siginfo-linus' of git://git.kernel.org/pub/scm/linux/kernel/git... (diff) | |
parent | of: unittest: fix an error code in of_unittest_apply_overlay() (diff) | |
download | linux-9c2dd8405c0cc2288d6098df40c19569d17553e4.tar.xz linux-9c2dd8405c0cc2288d6098df40c19569d17553e4.zip |
Merge tag 'devicetree-for-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
Pull DeviceTree updates from Rob Herring:
- Sync dtc to upstream version v1.4.6-9-gaadd0b65c987. This adds a
bunch more warnings (hidden behind W=1).
- Build dtc lexer and parser files instead of using shipped versions.
- Rework overlay apply API to take an FDT as input and apply overlays
in a single step.
- Add a phandle lookup cache. This improves boot time by hundreds of
msec on systems with large DT.
- Add trivial mcp4017/18/19 potentiometers bindings.
- Remove VLA stack usage in DT code.
* tag 'devicetree-for-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (26 commits)
of: unittest: fix an error code in of_unittest_apply_overlay()
of: unittest: move misplaced function declaration
of: unittest: Remove VLA stack usage
of: overlay: Fix forgotten reference to of_overlay_apply()
of: Documentation: Fix forgotten reference to of_overlay_apply()
of: unittest: local return value variable related cleanups
of: unittest: remove unneeded local return value variables
dt-bindings: trivial: add various mcp4017/18/19 potentiometers
of: unittest: fix an error test in of_unittest_overlay_8()
of: cache phandle nodes to reduce cost of of_find_node_by_phandle()
dt-bindings: rockchip-dw-mshc: use consistent clock names
MAINTAINERS: Add linux/of_*.h headers to appropriate subsystems
scripts: turn off some new dtc warnings by default
scripts/dtc: Update to upstream version v1.4.6-9-gaadd0b65c987
scripts/dtc: generate lexer and parser during build instead of shipping
powerpc: boot: add strrchr function
of: overlay: do not include path in full_name of added nodes
of: unittest: clean up changeset test
arm64/efi: Make strrchr() available to the EFI namespace
ARM: boot: add strrchr function
...
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/base.c | 270 | ||||
-rw-r--r-- | drivers/of/dynamic.c | 21 | ||||
-rw-r--r-- | drivers/of/of_private.h | 6 | ||||
-rw-r--r-- | drivers/of/overlay.c | 20 | ||||
-rw-r--r-- | drivers/of/resolver.c | 3 | ||||
-rw-r--r-- | drivers/of/unittest-data/tests-phandle.dtsi | 25 | ||||
-rw-r--r-- | drivers/of/unittest.c | 304 |
7 files changed, 525 insertions, 124 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index ad28de96e13f..848f549164cd 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -91,10 +91,72 @@ int __weak of_node_to_nid(struct device_node *np) } #endif +static struct device_node **phandle_cache; +static u32 phandle_cache_mask; + +/* + * Assumptions behind phandle_cache implementation: + * - phandle property values are in a contiguous range of 1..n + * + * If the assumptions do not hold, then + * - the phandle lookup overhead reduction provided by the cache + * will likely be less + */ +static void of_populate_phandle_cache(void) +{ + unsigned long flags; + u32 cache_entries; + struct device_node *np; + u32 phandles = 0; + + raw_spin_lock_irqsave(&devtree_lock, flags); + + kfree(phandle_cache); + phandle_cache = NULL; + + for_each_of_allnodes(np) + if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL) + phandles++; + + cache_entries = roundup_pow_of_two(phandles); + phandle_cache_mask = cache_entries - 1; + + phandle_cache = kcalloc(cache_entries, sizeof(*phandle_cache), + GFP_ATOMIC); + if (!phandle_cache) + goto out; + + for_each_of_allnodes(np) + if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL) + phandle_cache[np->phandle & phandle_cache_mask] = np; + +out: + raw_spin_unlock_irqrestore(&devtree_lock, flags); +} + +#ifndef CONFIG_MODULES +static int __init of_free_phandle_cache(void) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&devtree_lock, flags); + + kfree(phandle_cache); + phandle_cache = NULL; + + raw_spin_unlock_irqrestore(&devtree_lock, flags); + + return 0; +} +late_initcall_sync(of_free_phandle_cache); +#endif + void __init of_core_init(void) { struct device_node *np; + of_populate_phandle_cache(); + /* Create the kset, and register existing nodes */ mutex_lock(&of_mutex); of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); @@ -1021,16 +1083,32 @@ EXPORT_SYMBOL_GPL(of_modalias_node); */ struct device_node *of_find_node_by_phandle(phandle handle) { - struct device_node *np; + struct device_node *np = NULL; unsigned long flags; + phandle masked_handle; if (!handle) return NULL; raw_spin_lock_irqsave(&devtree_lock, flags); - for_each_of_allnodes(np) - if (np->phandle == handle) - break; + + masked_handle = handle & phandle_cache_mask; + + if (phandle_cache) { + if (phandle_cache[masked_handle] && + handle == phandle_cache[masked_handle]->phandle) + np = phandle_cache[masked_handle]; + } + + if (!np) { + for_each_of_allnodes(np) + if (np->phandle == handle) { + if (phandle_cache) + phandle_cache[masked_handle] = np; + break; + } + } + of_node_get(np); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np; @@ -1284,6 +1362,190 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na EXPORT_SYMBOL(of_parse_phandle_with_args); /** + * of_parse_phandle_with_args_map() - Find a node pointed by phandle in a list and remap it + * @np: pointer to a device tree node containing a list + * @list_name: property name that contains a list + * @stem_name: stem of property names that specify phandles' arguments count + * @index: index of a phandle to parse out + * @out_args: optional pointer to output arguments structure (will be filled) + * + * This function is useful to parse lists of phandles and their arguments. + * Returns 0 on success and fills out_args, on error returns appropriate errno + * value. The difference between this function and of_parse_phandle_with_args() + * is that this API remaps a phandle if the node the phandle points to has + * a <@stem_name>-map property. + * + * Caller is responsible to call of_node_put() on the returned out_args->np + * pointer. + * + * Example: + * + * phandle1: node1 { + * #list-cells = <2>; + * } + * + * phandle2: node2 { + * #list-cells = <1>; + * } + * + * phandle3: node3 { + * #list-cells = <1>; + * list-map = <0 &phandle2 3>, + * <1 &phandle2 2>, + * <2 &phandle1 5 1>; + * list-map-mask = <0x3>; + * }; + * + * node4 { + * list = <&phandle1 1 2 &phandle3 0>; + * } + * + * To get a device_node of the `node2' node you may call this: + * of_parse_phandle_with_args(node4, "list", "list", 1, &args); + */ +int of_parse_phandle_with_args_map(const struct device_node *np, + const char *list_name, + const char *stem_name, + int index, struct of_phandle_args *out_args) +{ + char *cells_name, *map_name = NULL, *mask_name = NULL; + char *pass_name = NULL; + struct device_node *cur, *new = NULL; + const __be32 *map, *mask, *pass; + static const __be32 dummy_mask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 }; + static const __be32 dummy_pass[] = { [0 ... MAX_PHANDLE_ARGS] = 0 }; + __be32 initial_match_array[MAX_PHANDLE_ARGS]; + const __be32 *match_array = initial_match_array; + int i, ret, map_len, match; + u32 list_size, new_size; + + if (index < 0) + return -EINVAL; + + cells_name = kasprintf(GFP_KERNEL, "#%s-cells", stem_name); + if (!cells_name) + return -ENOMEM; + + ret = -ENOMEM; + map_name = kasprintf(GFP_KERNEL, "%s-map", stem_name); + if (!map_name) + goto free; + + mask_name = kasprintf(GFP_KERNEL, "%s-map-mask", stem_name); + if (!mask_name) + goto free; + + pass_name = kasprintf(GFP_KERNEL, "%s-map-pass-thru", stem_name); + if (!pass_name) + goto free; + + ret = __of_parse_phandle_with_args(np, list_name, cells_name, 0, index, + out_args); + if (ret) + goto free; + + /* Get the #<list>-cells property */ + cur = out_args->np; + ret = of_property_read_u32(cur, cells_name, &list_size); + if (ret < 0) + goto put; + + /* Precalculate the match array - this simplifies match loop */ + for (i = 0; i < list_size; i++) + initial_match_array[i] = cpu_to_be32(out_args->args[i]); + + ret = -EINVAL; + while (cur) { + /* Get the <list>-map property */ + map = of_get_property(cur, map_name, &map_len); + if (!map) { + ret = 0; + goto free; + } + map_len /= sizeof(u32); + + /* Get the <list>-map-mask property (optional) */ + mask = of_get_property(cur, mask_name, NULL); + if (!mask) + mask = dummy_mask; + /* Iterate through <list>-map property */ + match = 0; + while (map_len > (list_size + 1) && !match) { + /* Compare specifiers */ + match = 1; + for (i = 0; i < list_size; i++, map_len--) + match &= !((match_array[i] ^ *map++) & mask[i]); + + of_node_put(new); + new = of_find_node_by_phandle(be32_to_cpup(map)); + map++; + map_len--; + + /* Check if not found */ + if (!new) + goto put; + + if (!of_device_is_available(new)) + match = 0; + + ret = of_property_read_u32(new, cells_name, &new_size); + if (ret) + goto put; + + /* Check for malformed properties */ + if (WARN_ON(new_size > MAX_PHANDLE_ARGS)) + goto put; + if (map_len < new_size) + goto put; + + /* Move forward by new node's #<list>-cells amount */ + map += new_size; + map_len -= new_size; + } + if (!match) + goto put; + + /* Get the <list>-map-pass-thru property (optional) */ + pass = of_get_property(cur, pass_name, NULL); + if (!pass) + pass = dummy_pass; + + /* + * Successfully parsed a <list>-map translation; copy new + * specifier into the out_args structure, keeping the + * bits specified in <list>-map-pass-thru. + */ + match_array = map - new_size; + for (i = 0; i < new_size; i++) { + __be32 val = *(map - new_size + i); + + if (i < list_size) { + val &= ~pass[i]; + val |= cpu_to_be32(out_args->args[i]) & pass[i]; + } + + out_args->args[i] = be32_to_cpu(val); + } + out_args->args_count = list_size = new_size; + /* Iterate again with new provider */ + out_args->np = new; + of_node_put(cur); + cur = new; + } +put: + of_node_put(cur); + of_node_put(new); +free: + kfree(mask_name); + kfree(map_name); + kfree(cells_name); + kfree(pass_name); + + return ret; +} +EXPORT_SYMBOL(of_parse_phandle_with_args_map); + +/** * of_parse_phandle_with_fixed_args() - Find a node pointed by phandle in a list * @np: pointer to a device tree node containing a list * @list_name: property name that contains a list diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index 7bb33d22b4e2..f4f8ed9b5454 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -383,25 +383,24 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags) /** * __of_node_dup() - Duplicate or create an empty device node dynamically. - * @fmt: Format string (plus vargs) for new full name of the device node + * @np: if not NULL, contains properties to be duplicated in new node + * @full_name: string value to be duplicated into new node's full_name field * - * Create an device tree node, either by duplicating an empty node or by allocating - * an empty one suitable for further modification. The node data are - * dynamically allocated and all the node flags have the OF_DYNAMIC & - * OF_DETACHED bits set. Returns the newly allocated node or NULL on out of - * memory error. + * Create a device tree node, optionally duplicating the properties of + * another node. The node data are dynamically allocated and all the node + * flags have the OF_DYNAMIC & OF_DETACHED bits set. + * + * Returns the newly allocated node or NULL on out of memory error. */ -struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...) +struct device_node *__of_node_dup(const struct device_node *np, + const char *full_name) { - va_list vargs; struct device_node *node; node = kzalloc(sizeof(*node), GFP_KERNEL); if (!node) return NULL; - va_start(vargs, fmt); - node->full_name = kvasprintf(GFP_KERNEL, fmt, vargs); - va_end(vargs); + node->full_name = kstrdup(full_name, GFP_KERNEL); if (!node->full_name) { kfree(node); return NULL; diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index 0c609e7d0334..891d780c076a 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -104,7 +104,8 @@ extern void *__unflatten_device_tree(const void *blob, * own the devtree lock or work on detached trees only. */ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags); -__printf(2, 3) struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...); +struct device_node *__of_node_dup(const struct device_node *np, + const char *full_name); struct device_node *__of_find_node_by_path(struct device_node *parent, const char *path); @@ -131,6 +132,9 @@ extern void __of_detach_node_sysfs(struct device_node *np); extern void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop); +/* illegal phandle value (set when unresolved) */ +#define OF_PHANDLE_ILLEGAL 0xdeadbeef + /* iterators for transactions, used for overlays */ /* forward iterator */ #define for_each_transaction_entry(_oft, _te) \ diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index b930e05d1215..b35fe88f1851 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -312,7 +312,20 @@ static int add_changeset_property(struct overlay_changeset *ovcs, * If @node has child nodes, add the children recursively via * build_changeset_next_level(). * - * NOTE: Multiple mods of created nodes not supported. + * NOTE_1: A live devicetree created from a flattened device tree (FDT) will + * not contain the full path in node->full_name. Thus an overlay + * created from an FDT also will not contain the full path in + * node->full_name. However, a live devicetree created from Open + * Firmware may have the full path in node->full_name. + * + * add_changeset_node() follows the FDT convention and does not include + * the full path in node->full_name. Even though it expects the overlay + * to not contain the full path, it uses kbasename() to remove the + * full path should it exist. It also uses kbasename() in comparisons + * to nodes in the live devicetree so that it can apply an overlay to + * a live devicetree created from Open Firmware. + * + * NOTE_2: Multiple mods of created nodes not supported. * If more than one fragment contains a node that does not already exist * in the live tree, then for each fragment of_changeset_attach_node() * will add a changeset entry to add the node. When the changeset is @@ -339,8 +352,7 @@ static int add_changeset_node(struct overlay_changeset *ovcs, break; if (!tchild) { - tchild = __of_node_dup(node, "%pOF/%s", - target_node, node_kbasename); + tchild = __of_node_dup(node, node_kbasename); if (!tchild) return -ENOMEM; @@ -958,7 +970,7 @@ static int overlay_removal_is_ok(struct overlay_changeset *remove_ovcs) * @ovcs_id: Pointer to overlay changeset id * * Removes an overlay if it is permissible. @ovcs_id was previously returned - * by of_overlay_apply(). + * by of_overlay_fdt_apply(). * * If an error occurred while attempting to revert the overlay changeset, * then an attempt is made to re-apply any changeset entry that was diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index b2f645187213..65d0b7adfcd4 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -19,9 +19,6 @@ #include "of_private.h" -/* illegal phandle value (set when unresolved) */ -#define OF_PHANDLE_ILLEGAL 0xdeadbeef - static phandle live_tree_max_phandle(void) { struct device_node *node; diff --git a/drivers/of/unittest-data/tests-phandle.dtsi b/drivers/of/unittest-data/tests-phandle.dtsi index 3c2f09e56b61..6b33be4c4416 100644 --- a/drivers/of/unittest-data/tests-phandle.dtsi +++ b/drivers/of/unittest-data/tests-phandle.dtsi @@ -26,6 +26,18 @@ #phandle-cells = <3>; }; + provider4: provider4 { + #phandle-cells = <2>; + phandle-map = <0 1 &provider1 3>, + <4 0 &provider0>, + <16 5 &provider3 3 5 0>, + <200 8 &provider2 23 6>, + <19 0 &provider2 15 0>, + <2 3 &provider3 2 5 3>; + phandle-map-mask = <0xff 0xf>; + phandle-map-pass-thru = <0x0 0xf0>; + }; + consumer-a { phandle-list = <&provider1 1>, <&provider2 2 0>, @@ -44,6 +56,19 @@ unterminated-string = [40 41 42 43]; unterminated-string-list = "first", "second", [40 41 42 43]; }; + + consumer-b { + phandle-list = <&provider1 1>, + <&provider4 2 3>, + <0>, + <&provider4 4 0x100>, + <&provider4 0 0x61>, + <&provider0>, + <&provider4 19 0x20>; + phandle-list-bad-phandle = <12345678 0 0>; + phandle-list-bad-args = <&provider2 1 0>, + <&provider4 0>; + }; }; }; }; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index a23b54780c7d..02c5984ab09b 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -45,8 +45,6 @@ static struct unittest_results { failed; \ }) -static int __init overlay_data_apply(const char *overlay_name, int *overlay_id); - static void __init of_unittest_find_node_by_name(void) { struct device_node *np; @@ -254,12 +252,18 @@ static void __init of_unittest_check_tree_linkage(void) static void __init of_unittest_printf_one(struct device_node *np, const char *fmt, const char *expected) { - unsigned char buf[strlen(expected)+10]; + unsigned char *buf; + int buf_size; int size, i; + buf_size = strlen(expected) + 10; + buf = kmalloc(buf_size, GFP_KERNEL); + if (!buf) + return; + /* Baseline; check conversion with a large size limit */ - memset(buf, 0xff, sizeof(buf)); - size = snprintf(buf, sizeof(buf) - 2, fmt, np); + memset(buf, 0xff, buf_size); + size = snprintf(buf, buf_size - 2, fmt, np); /* use strcmp() instead of strncmp() here to be absolutely sure strings match */ unittest((strcmp(buf, expected) == 0) && (buf[size+1] == 0xff), @@ -270,12 +274,13 @@ static void __init of_unittest_printf_one(struct device_node *np, const char *fm size++; for (i = 0; i < 2; i++, size--) { /* Clear the buffer, and make sure it works correctly still */ - memset(buf, 0xff, sizeof(buf)); + memset(buf, 0xff, buf_size); snprintf(buf, size+1, fmt, np); unittest(strncmp(buf, expected, size) == 0 && (buf[size+1] == 0xff), "snprintf failed; size=%i fmt='%s' expected='%s' rslt='%s'\n", size, fmt, expected, buf); } + kfree(buf); } static void __init of_unittest_printf(void) @@ -455,6 +460,125 @@ static void __init of_unittest_parse_phandle_with_args(void) unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); } +static void __init of_unittest_parse_phandle_with_args_map(void) +{ + struct device_node *np, *p0, *p1, *p2, *p3; + struct of_phandle_args args; + int i, rc; + + np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-b"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + p0 = of_find_node_by_path("/testcase-data/phandle-tests/provider0"); + if (!p0) { + pr_err("missing testcase data\n"); + return; + } + + p1 = of_find_node_by_path("/testcase-data/phandle-tests/provider1"); + if (!p1) { + pr_err("missing testcase data\n"); + return; + } + + p2 = of_find_node_by_path("/testcase-data/phandle-tests/provider2"); + if (!p2) { + pr_err("missing testcase data\n"); + return; + } + + p3 = of_find_node_by_path("/testcase-data/phandle-tests/provider3"); + if (!p3) { + pr_err("missing testcase data\n"); + return; + } + + rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells"); + unittest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc); + + for (i = 0; i < 8; i++) { + bool passed = true; + + rc = of_parse_phandle_with_args_map(np, "phandle-list", + "phandle", i, &args); + + /* Test the values from tests-phandle.dtsi */ + switch (i) { + case 0: + passed &= !rc; + passed &= (args.np == p1); + passed &= (args.args_count == 1); + passed &= (args.args[0] == 1); + break; + case 1: + passed &= !rc; + passed &= (args.np == p3); + passed &= (args.args_count == 3); + passed &= (args.args[0] == 2); + passed &= (args.args[1] == 5); + passed &= (args.args[2] == 3); + break; + case 2: + passed &= (rc == -ENOENT); + break; + case 3: + passed &= !rc; + passed &= (args.np == p0); + passed &= (args.args_count == 0); + break; + case 4: + passed &= !rc; + passed &= (args.np == p1); + passed &= (args.args_count == 1); + passed &= (args.args[0] == 3); + break; + case 5: + passed &= !rc; + passed &= (args.np == p0); + passed &= (args.args_count == 0); + break; + case 6: + passed &= !rc; + passed &= (args.np == p2); + passed &= (args.args_count == 2); + passed &= (args.args[0] == 15); + passed &= (args.args[1] == 0x20); + break; + case 7: + passed &= (rc == -ENOENT); + break; + default: + passed = false; + } + + unittest(passed, "index %i - data error on node %s rc=%i\n", + i, args.np->full_name, rc); + } + + /* Check for missing list property */ + rc = of_parse_phandle_with_args_map(np, "phandle-list-missing", + "phandle", 0, &args); + unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc); + + /* Check for missing cells,map,mask property */ + rc = of_parse_phandle_with_args_map(np, "phandle-list", + "phandle-missing", 0, &args); + unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); + + /* Check for bad phandle in list */ + rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-phandle", + "phandle", 0, &args); + unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); + + /* Check for incorrectly formed argument list */ + rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-args", + "phandle", 1, &args); + unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); +} + static void __init of_unittest_property_string(void) { const char *strings[4]; @@ -564,42 +688,72 @@ static void __init of_unittest_property_copy(void) static void __init of_unittest_changeset(void) { #ifdef CONFIG_OF_DYNAMIC - struct property *ppadd, padd = { .name = "prop-add", .length = 0, .value = "" }; + struct property *ppadd, padd = { .name = "prop-add", .length = 1, .value = "" }; + struct property *ppname_n1, pname_n1 = { .name = "name", .length = 3, .value = "n1" }; + struct property *ppname_n2, pname_n2 = { .name = "name", .length = 3, .value = "n2" }; + struct property *ppname_n21, pname_n21 = { .name = "name", .length = 3, .value = "n21" }; struct property *ppupdate, pupdate = { .name = "prop-update", .length = 5, .value = "abcd" }; struct property *ppremove; - struct device_node *n1, *n2, *n21, *nremove, *parent, *np; + struct device_node *n1, *n2, *n21, *nchangeset, *nremove, *parent, *np; struct of_changeset chgset; - n1 = __of_node_dup(NULL, "/testcase-data/changeset/n1"); + n1 = __of_node_dup(NULL, "n1"); unittest(n1, "testcase setup failure\n"); - n2 = __of_node_dup(NULL, "/testcase-data/changeset/n2"); + + n2 = __of_node_dup(NULL, "n2"); unittest(n2, "testcase setup failure\n"); - n21 = __of_node_dup(NULL, "%s/%s", "/testcase-data/changeset/n2", "n21"); + + n21 = __of_node_dup(NULL, "n21"); unittest(n21, "testcase setup failure %p\n", n21); - nremove = of_find_node_by_path("/testcase-data/changeset/node-remove"); + + nchangeset = of_find_node_by_path("/testcase-data/changeset"); + nremove = of_get_child_by_name(nchangeset, "node-remove"); unittest(nremove, "testcase setup failure\n"); + ppadd = __of_prop_dup(&padd, GFP_KERNEL); unittest(ppadd, "testcase setup failure\n"); + + ppname_n1 = __of_prop_dup(&pname_n1, GFP_KERNEL); + unittest(ppname_n1, "testcase setup failure\n"); + + ppname_n2 = __of_prop_dup(&pname_n2, GFP_KERNEL); + unittest(ppname_n2, "testcase setup failure\n"); + + ppname_n21 = __of_prop_dup(&pname_n21, GFP_KERNEL); + unittest(ppname_n21, "testcase setup failure\n"); + ppupdate = __of_prop_dup(&pupdate, GFP_KERNEL); unittest(ppupdate, "testcase setup failure\n"); - parent = nremove->parent; + + parent = nchangeset; n1->parent = parent; n2->parent = parent; n21->parent = n2; - n2->child = n21; + ppremove = of_find_property(parent, "prop-remove", NULL); unittest(ppremove, "failed to find removal prop"); of_changeset_init(&chgset); + unittest(!of_changeset_attach_node(&chgset, n1), "fail attach n1\n"); + unittest(!of_changeset_add_property(&chgset, n1, ppname_n1), "fail add prop name\n"); + unittest(!of_changeset_attach_node(&chgset, n2), "fail attach n2\n"); + unittest(!of_changeset_add_property(&chgset, n2, ppname_n2), "fail add prop name\n"); + unittest(!of_changeset_detach_node(&chgset, nremove), "fail remove node\n"); + unittest(!of_changeset_add_property(&chgset, n21, ppname_n21), "fail add prop name\n"); + unittest(!of_changeset_attach_node(&chgset, n21), "fail attach n21\n"); - unittest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop\n"); + + unittest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop prop-add\n"); unittest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n"); unittest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n"); + unittest(!of_changeset_apply(&chgset), "apply failed\n"); + of_node_put(nchangeset); + /* Make sure node names are constructed correctly */ unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")), "'%pOF' not added\n", n21); @@ -1036,6 +1190,7 @@ static int __init unittest_data_add(void) } #ifdef CONFIG_OF_OVERLAY +static int __init overlay_data_apply(const char *overlay_name, int *overlay_id); static int unittest_probe(struct platform_device *pdev) { @@ -1267,26 +1422,18 @@ static void of_unittest_destroy_tracked_overlays(void) static int __init of_unittest_apply_overlay(int overlay_nr, int unittest_nr, int *overlay_id) { - struct device_node *np = NULL; const char *overlay_name; - int ret; overlay_name = overlay_name_from_nr(overlay_nr); - ret = overlay_data_apply(overlay_name, overlay_id); - if (!ret) { + if (!overlay_data_apply(overlay_name, overlay_id)) { unittest(0, "could not apply overlay \"%s\"\n", overlay_name); - goto out; + return -EFAULT; } of_unittest_track_overlay(*overlay_id); - ret = 0; - -out: - of_node_put(np); - - return ret; + return 0; } /* apply an overlay while checking before and after states */ @@ -1380,11 +1527,8 @@ static int __init of_unittest_apply_revert_overlay_check(int overlay_nr, /* test activation of device */ static void __init of_unittest_overlay_0(void) { - int ret; - /* device should enable */ - ret = of_unittest_apply_overlay_check(0, 0, 0, 1, PDEV_OVERLAY); - if (ret != 0) + if (of_unittest_apply_overlay_check(0, 0, 0, 1, PDEV_OVERLAY)) return; unittest(1, "overlay test %d passed\n", 0); @@ -1393,11 +1537,8 @@ static void __init of_unittest_overlay_0(void) /* test deactivation of device */ static void __init of_unittest_overlay_1(void) { - int ret; - /* device should disable */ - ret = of_unittest_apply_overlay_check(1, 1, 1, 0, PDEV_OVERLAY); - if (ret != 0) + if (of_unittest_apply_overlay_check(1, 1, 1, 0, PDEV_OVERLAY)) return; unittest(1, "overlay test %d passed\n", 1); @@ -1406,11 +1547,8 @@ static void __init of_unittest_overlay_1(void) /* test activation of device */ static void __init of_unittest_overlay_2(void) { - int ret; - /* device should enable */ - ret = of_unittest_apply_overlay_check(2, 2, 0, 1, PDEV_OVERLAY); - if (ret != 0) + if (of_unittest_apply_overlay_check(2, 2, 0, 1, PDEV_OVERLAY)) return; unittest(1, "overlay test %d passed\n", 2); @@ -1419,11 +1557,8 @@ static void __init of_unittest_overlay_2(void) /* test deactivation of device */ static void __init of_unittest_overlay_3(void) { - int ret; - /* device should disable */ - ret = of_unittest_apply_overlay_check(3, 3, 1, 0, PDEV_OVERLAY); - if (ret != 0) + if (of_unittest_apply_overlay_check(3, 3, 1, 0, PDEV_OVERLAY)) return; unittest(1, "overlay test %d passed\n", 3); @@ -1432,11 +1567,8 @@ static void __init of_unittest_overlay_3(void) /* test activation of a full device node */ static void __init of_unittest_overlay_4(void) { - int ret; - /* device should disable */ - ret = of_unittest_apply_overlay_check(4, 4, 0, 1, PDEV_OVERLAY); - if (ret != 0) + if (of_unittest_apply_overlay_check(4, 4, 0, 1, PDEV_OVERLAY)) return; unittest(1, "overlay test %d passed\n", 4); @@ -1445,11 +1577,8 @@ static void __init of_unittest_overlay_4(void) /* test overlay apply/revert sequence */ static void __init of_unittest_overlay_5(void) { - int ret; - /* device should disable */ - ret = of_unittest_apply_revert_overlay_check(5, 5, 0, 1, PDEV_OVERLAY); - if (ret != 0) + if (of_unittest_apply_revert_overlay_check(5, 5, 0, 1, PDEV_OVERLAY)) return; unittest(1, "overlay test %d passed\n", 5); @@ -1458,7 +1587,7 @@ static void __init of_unittest_overlay_5(void) /* test overlay application in sequence */ static void __init of_unittest_overlay_6(void) { - int ret, i, ov_id[2], ovcs_id; + int i, ov_id[2], ovcs_id; int overlay_nr = 6, unittest_nr = 6; int before = 0, after = 1; const char *overlay_name; @@ -1481,8 +1610,7 @@ static void __init of_unittest_overlay_6(void) overlay_name = overlay_name_from_nr(overlay_nr + i); - ret = overlay_data_apply(overlay_name, &ovcs_id); - if (!ret) { + if (!overlay_data_apply(overlay_name, &ovcs_id)) { unittest(0, "could not apply overlay \"%s\"\n", overlay_name); return; @@ -1506,8 +1634,7 @@ static void __init of_unittest_overlay_6(void) for (i = 1; i >= 0; i--) { ovcs_id = ov_id[i]; - ret = of_overlay_remove(&ovcs_id); - if (ret != 0) { + if (of_overlay_remove(&ovcs_id)) { unittest(0, "%s failed destroy @\"%s\"\n", overlay_name_from_nr(overlay_nr + i), unittest_path(unittest_nr + i, @@ -1536,7 +1663,7 @@ static void __init of_unittest_overlay_6(void) /* test overlay application in sequence */ static void __init of_unittest_overlay_8(void) { - int ret, i, ov_id[2], ovcs_id; + int i, ov_id[2], ovcs_id; int overlay_nr = 8, unittest_nr = 8; const char *overlay_name; @@ -1547,8 +1674,7 @@ static void __init of_unittest_overlay_8(void) overlay_name = overlay_name_from_nr(overlay_nr + i); - ret = overlay_data_apply(overlay_name, &ovcs_id); - if (ret < 0) { + if (!overlay_data_apply(overlay_name, &ovcs_id)) { unittest(0, "could not apply overlay \"%s\"\n", overlay_name); return; @@ -1559,8 +1685,7 @@ static void __init of_unittest_overlay_8(void) /* now try to remove first overlay (it should fail) */ ovcs_id = ov_id[0]; - ret = of_overlay_remove(&ovcs_id); - if (ret == 0) { + if (!of_overlay_remove(&ovcs_id)) { unittest(0, "%s was destroyed @\"%s\"\n", overlay_name_from_nr(overlay_nr + 0), unittest_path(unittest_nr, @@ -1571,8 +1696,7 @@ static void __init of_unittest_overlay_8(void) /* removing them in order should work */ for (i = 1; i >= 0; i--) { ovcs_id = ov_id[i]; - ret = of_overlay_remove(&ovcs_id); - if (ret != 0) { + if (of_overlay_remove(&ovcs_id)) { unittest(0, "%s not destroyed @\"%s\"\n", overlay_name_from_nr(overlay_nr + i), unittest_path(unittest_nr, @@ -1604,8 +1728,8 @@ static void __init of_unittest_overlay_10(void) ret = of_path_device_type_exists(child_path, PDEV_OVERLAY); kfree(child_path); - if (unittest(ret, "overlay test %d failed; no child device\n", 10)) - return; + + unittest(ret, "overlay test %d failed; no child device\n", 10); } /* test insertion of a bus with parent devices (and revert) */ @@ -1616,9 +1740,7 @@ static void __init of_unittest_overlay_11(void) /* device should disable */ ret = of_unittest_apply_revert_overlay_check(11, 11, 0, 1, PDEV_OVERLAY); - if (unittest(ret == 0, - "overlay test %d failed; overlay application\n", 11)) - return; + unittest(ret == 0, "overlay test %d failed; overlay apply\n", 11); } #if IS_BUILTIN(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY) @@ -1769,7 +1891,7 @@ static int unittest_i2c_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) static int unittest_i2c_mux_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int ret, i, nchans; + int i, nchans; struct device *dev = &client->dev; struct i2c_adapter *adap = to_i2c_adapter(dev->parent); struct device_node *np = client->dev.of_node, *child; @@ -1785,8 +1907,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client, max_reg = (u32)-1; for_each_child_of_node(np, child) { - ret = of_property_read_u32(child, "reg", ®); - if (ret) + if (of_property_read_u32(child, "reg", ®)) continue; if (max_reg == (u32)-1 || reg > max_reg) max_reg = reg; @@ -1802,8 +1923,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client, if (!muxc) return -ENOMEM; for (i = 0; i < nchans; i++) { - ret = i2c_mux_add_adapter(muxc, 0, i, 0); - if (ret) { + if (i2c_mux_add_adapter(muxc, 0, i, 0)) { dev_err(dev, "Failed to register mux #%d\n", i); i2c_mux_del_adapters(muxc); return -ENODEV; @@ -1877,11 +1997,8 @@ static void of_unittest_overlay_i2c_cleanup(void) static void __init of_unittest_overlay_i2c_12(void) { - int ret; - /* device should enable */ - ret = of_unittest_apply_overlay_check(12, 12, 0, 1, I2C_OVERLAY); - if (ret != 0) + if (of_unittest_apply_overlay_check(12, 12, 0, 1, I2C_OVERLAY)) return; unittest(1, "overlay test %d passed\n", 12); @@ -1890,11 +2007,8 @@ static void __init of_unittest_overlay_i2c_12(void) /* test deactivation of device */ static void __init of_unittest_overlay_i2c_13(void) { - int ret; - /* device should disable */ - ret = of_unittest_apply_overlay_check(13, 13, 1, 0, I2C_OVERLAY); - if (ret != 0) + if (of_unittest_apply_overlay_check(13, 13, 1, 0, I2C_OVERLAY)) return; unittest(1, "overlay test %d passed\n", 13); @@ -1907,11 +2021,8 @@ static void of_unittest_overlay_i2c_14(void) static void __init of_unittest_overlay_i2c_15(void) { - int ret; - /* device should enable */ - ret = of_unittest_apply_overlay_check(15, 15, 0, 1, I2C_OVERLAY); - if (ret != 0) + if (of_unittest_apply_overlay_check(15, 15, 0, 1, I2C_OVERLAY)) return; unittest(1, "overlay test %d passed\n", 15); @@ -1927,10 +2038,8 @@ static inline void of_unittest_overlay_i2c_15(void) { } static void __init of_unittest_overlay(void) { struct device_node *bus_np = NULL; - int ret; - ret = platform_driver_register(&unittest_driver); - if (ret != 0) { + if (platform_driver_register(&unittest_driver)) { unittest(0, "could not register unittest driver\n"); goto out; } @@ -1941,8 +2050,7 @@ static void __init of_unittest_overlay(void) goto out; } - ret = of_platform_default_populate(bus_np, NULL, NULL); - if (ret != 0) { + if (of_platform_default_populate(bus_np, NULL, NULL)) { unittest(0, "could not populate bus @ \"%s\"\n", bus_path); goto out; } @@ -2156,10 +2264,8 @@ static int __init overlay_data_apply(const char *overlay_name, int *overlay_id) } size = info->dtb_end - info->dtb_begin; - if (!size) { + if (!size) pr_err("no overlay data for %s\n", overlay_name); - ret = 0; - } ret = of_overlay_fdt_apply(info->dtb_begin, size, &info->overlay_id); if (overlay_id) @@ -2193,7 +2299,6 @@ static __init void of_unittest_overlay_high_level(void) struct device_node *overlay_base_symbols; struct device_node **pprev; struct property *prop; - int ret; if (!overlay_base_root) { unittest(0, "overlay_base_root not initialized\n"); @@ -2284,19 +2389,15 @@ static __init void of_unittest_overlay_high_level(void) prop->name); goto err_unlock; } - ret = __of_add_property(of_symbols, new_prop); - if (ret) { - if (!strcmp(new_prop->name, "name")) { - /* auto-generated by unflatten */ - ret = 0; + if (__of_add_property(of_symbols, new_prop)) { + /* "name" auto-generated by unflatten */ + if (!strcmp(new_prop->name, "name")) continue; - } unittest(0, "duplicate property '%s' in overlay_base node __symbols__", prop->name); goto err_unlock; } - ret = __of_add_property_sysfs(of_symbols, new_prop); - if (ret) { + if (__of_add_property_sysfs(of_symbols, new_prop)) { unittest(0, "unable to add property '%s' in overlay_base node __symbols__ to sysfs", prop->name); goto err_unlock; @@ -2355,6 +2456,7 @@ static int __init of_unittest(void) of_unittest_find_node_by_name(); of_unittest_dynamic(); of_unittest_parse_phandle_with_args(); + of_unittest_parse_phandle_with_args_map(); of_unittest_printf(); of_unittest_property_string(); of_unittest_property_copy(); |