diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/boot/vbe_simple.c | 25 | ||||
-rw-r--r-- | test/dm/ofnode.c | 696 | ||||
-rw-r--r-- | test/dm/ofread.c | 11 | ||||
-rw-r--r-- | test/image/spl_load.c | 4 | ||||
-rw-r--r-- | test/test-main.c | 132 |
5 files changed, 809 insertions, 59 deletions
diff --git a/test/boot/vbe_simple.c b/test/boot/vbe_simple.c index 2f6979cafcf..8acd777f4cd 100644 --- a/test/boot/vbe_simple.c +++ b/test/boot/vbe_simple.c @@ -74,29 +74,25 @@ static int vbe_simple_test_base(struct unit_test_state *uts) node_ofs = fdt_add_subnode(fdt_buf, node_ofs, "firmware0"); ut_assert(node_ofs > 0); - /* - * This can only work on the live tree, since the ofnode interface for - * flat tree assumes that ofnode points to the control FDT - */ - ut_assertok(unflatten_device_tree(fdt_buf, &np)); + if (of_live_active()) { + ut_assertok(unflatten_device_tree(fdt_buf, &np)); + fixup.tree = oftree_from_np(np); + } else { + fixup.tree = oftree_from_fdt(fdt_buf); + } /* * It would be better to call image_setup_libfdt() here, but that * function does not allow passing an ofnode. We can pass fdt_buf but - * when it comes to send the evenr, it creates an ofnode that uses the + * when it comes to send the event, it creates an ofnode that uses the * control FDT, since it has no way of accessing the live tree created * here. * - * Two fix this we need: - * - image_setup_libfdt() is updated to use ofnode - * - ofnode updated to support access to an FDT other than the control - * FDT. This is partially implemented with live tree, but not with - * flat tree + * Two fix this we need image_setup_libfdt() is updated to use ofnode */ - fixup.tree.np = np; ut_assertok(event_notify(EVT_FT_FIXUP, &fixup, sizeof(fixup))); - node = ofnode_path_root(fixup.tree, "/chosen/fwupd/firmware0"); + node = oftree_path(fixup.tree, "/chosen/fwupd/firmware0"); version = ofnode_read_string(node, "cur-version"); ut_assertnonnull(version); @@ -111,5 +107,4 @@ static int vbe_simple_test_base(struct unit_test_state *uts) return 0; } -BOOTSTD_TEST(vbe_simple_test_base, UT_TESTF_DM | UT_TESTF_SCAN_FDT | - UT_TESTF_LIVE_TREE); +BOOTSTD_TEST(vbe_simple_test_base, UT_TESTF_DM | UT_TESTF_SCAN_FDT); diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index f80993f8927..41811ec3bb5 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -1,4 +1,20 @@ // SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2022 Google LLC + * + * There are two types of tests in this file: + * - normal ones which act on the control FDT (gd->fdt_blob or gd->of_root) + * - 'other' ones which act on the 'other' FDT (other.dts) + * + * The 'other' ones have an _ot suffix. + * + * The latter are used to check behaviour with multiple device trees, + * particularly with flat tree, where a tree ID is included in ofnode as part of + * the node offset. These tests are typically just for making sure that the + * offset makes it to libfdt correctly and that the resulting return value is + * correctly turned into an ofnode. The 'other' tests do not fully check the + * behaviour of each ofnode function, since that is done by the normal ones. + */ #include <common.h> #include <dm.h> @@ -13,6 +29,68 @@ #include <test/test.h> #include <test/ut.h> +/** + * get_other_oftree() - Convert a flat tree into an oftree object + * + * @uts: Test state + * @return: oftree object for the 'other' FDT (see sandbox' other.dts) + */ +oftree get_other_oftree(struct unit_test_state *uts) +{ + oftree tree; + + if (of_live_active()) + tree = oftree_from_np(uts->of_other); + else + tree = oftree_from_fdt(uts->other_fdt); + + /* An invalid tree may cause failure or crashes */ + if (!oftree_valid(tree)) + ut_reportf("test needs the UT_TESTF_OTHER_FDT flag"); + + return tree; +} + +/** + * get_oftree() - Convert a flat tree into an oftree object + * + * @uts: Test state + * @fdt: Pointer to flat tree + * @treep: Returns the tree, on success + * Return: 0 if OK, 1 if the tree failed to unflatten, -EOVERFLOW if there are + * too many flat trees to allow another one to be registers (see + * oftree_ensure()) + */ +int get_oftree(struct unit_test_state *uts, void *fdt, oftree *treep) +{ + oftree tree; + + if (of_live_active()) { + struct device_node *root; + + ut_assertok(unflatten_device_tree(fdt, &root)); + tree = oftree_from_np(root); + } else { + tree = oftree_from_fdt(fdt); + if (!oftree_valid(tree)) + return -EOVERFLOW; + } + *treep = tree; + + return 0; +} + +/** + * free_oftree() - Free memory used by get_oftree() + * + * @tree: Tree to free + */ +void free_oftree(oftree tree) +{ + if (of_live_active()) + free(tree.np); +} + static int dm_test_ofnode_compatible(struct unit_test_state *uts) { ofnode root_node = ofnode_path("/"); @@ -22,7 +100,21 @@ static int dm_test_ofnode_compatible(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_compatible, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +DM_TEST(dm_test_ofnode_compatible, + UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +/* check ofnode_device_is_compatible() with the 'other' FDT */ +static int dm_test_ofnode_compatible_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + ofnode oroot = oftree_root(otree); + + ut_assert(ofnode_valid(oroot)); + ut_assert(ofnode_device_is_compatible(oroot, "sandbox-other")); + + return 0; +} +DM_TEST(dm_test_ofnode_compatible_ot, UT_TESTF_OTHER_FDT); static int dm_test_ofnode_get_by_phandle(struct unit_test_state *uts) { @@ -36,37 +128,76 @@ static int dm_test_ofnode_get_by_phandle(struct unit_test_state *uts) /* test unknown phandle */ ut_assert(!ofnode_valid(ofnode_get_by_phandle(0x1000000))); + ut_assert(ofnode_valid(oftree_get_by_phandle(oftree_default(), 1))); + return 0; } DM_TEST(dm_test_ofnode_get_by_phandle, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); -static int dm_test_ofnode_by_prop_value(struct unit_test_state *uts) +static int dm_test_ofnode_get_by_phandle_ot(struct unit_test_state *uts) { - const char propname[] = "compatible"; - const char propval[] = "denx,u-boot-fdt-test"; + oftree otree = get_other_oftree(uts); + ofnode node; + + ut_assert(ofnode_valid(oftree_get_by_phandle(oftree_default(), 1))); + node = oftree_get_by_phandle(otree, 1); + ut_assert(ofnode_valid(node)); + ut_asserteq_str("target", ofnode_get_name(node)); + + return 0; +} +DM_TEST(dm_test_ofnode_get_by_phandle_ot, UT_TESTF_OTHER_FDT); + +static int check_prop_values(struct unit_test_state *uts, ofnode start, + const char *propname, const char *propval, + int expect_count) +{ + int proplen = strlen(propval) + 1; const char *str; - ofnode node = ofnode_null(); + ofnode node; + int count; /* Find first matching node, there should be at least one */ - node = ofnode_by_prop_value(node, propname, propval, sizeof(propval)); + node = ofnode_by_prop_value(start, propname, propval, proplen); ut_assert(ofnode_valid(node)); str = ofnode_read_string(node, propname); ut_assert(str && !strcmp(str, propval)); /* Find the rest of the matching nodes */ + count = 1; while (true) { - node = ofnode_by_prop_value(node, propname, propval, - sizeof(propval)); + node = ofnode_by_prop_value(node, propname, propval, proplen); if (!ofnode_valid(node)) break; str = ofnode_read_string(node, propname); - ut_assert(str && !strcmp(str, propval)); + ut_asserteq_str(propval, str); + count++; } + ut_asserteq(expect_count, count); + + return 0; +} + +static int dm_test_ofnode_by_prop_value(struct unit_test_state *uts) +{ + ut_assertok(check_prop_values(uts, ofnode_null(), "compatible", + "denx,u-boot-fdt-test", 11)); return 0; } DM_TEST(dm_test_ofnode_by_prop_value, UT_TESTF_SCAN_FDT); +static int dm_test_ofnode_by_prop_value_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + + ut_assertok(check_prop_values(uts, oftree_root(otree), "str-prop", + "other", 2)); + + return 0; +} +DM_TEST(dm_test_ofnode_by_prop_value_ot, UT_TESTF_OTHER_FDT); + static int dm_test_ofnode_fmap(struct unit_test_state *uts) { struct fmap_entry entry; @@ -108,6 +239,25 @@ static int dm_test_ofnode_read(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_read, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +static int dm_test_ofnode_read_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + const char *val; + ofnode node; + int size; + + node = oftree_path(otree, "/node/subnode"); + ut_assert(ofnode_valid(node)); + + val = ofnode_read_prop(node, "str-prop", &size); + ut_assertnonnull(val); + ut_asserteq_str("other", val); + ut_asserteq(6, size); + + return 0; +} +DM_TEST(dm_test_ofnode_read_ot, UT_TESTF_OTHER_FDT); + static int dm_test_ofnode_phandle(struct unit_test_state *uts) { struct ofnode_phandle_args args; @@ -183,6 +333,34 @@ static int dm_test_ofnode_phandle(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_phandle, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +static int dm_test_ofnode_phandle_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + struct ofnode_phandle_args args; + ofnode node; + int ret; + + node = oftree_path(otree, "/node"); + + /* Test ofnode_count_phandle_with_args with cell name */ + ret = ofnode_count_phandle_with_args(node, "missing", "#gpio-cells", 0); + ut_asserteq(-ENOENT, ret); + ret = ofnode_count_phandle_with_args(node, "target", "#invalid", 0); + ut_asserteq(-EINVAL, ret); + ret = ofnode_count_phandle_with_args(node, "target", "#gpio-cells", 0); + ut_asserteq(1, ret); + + ret = ofnode_parse_phandle_with_args(node, "target", "#gpio-cells", 0, + 0, &args); + ut_assertok(ret); + ut_asserteq(2, args.args_count); + ut_asserteq(3, args.args[0]); + ut_asserteq(4, args.args[1]); + + return 0; +} +DM_TEST(dm_test_ofnode_phandle_ot, UT_TESTF_OTHER_FDT); + static int dm_test_ofnode_read_chosen(struct unit_test_state *uts) { const char *str; @@ -255,6 +433,27 @@ static int dm_test_ofnode_get_child_count(struct unit_test_state *uts) DM_TEST(dm_test_ofnode_get_child_count, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +static int dm_test_ofnode_get_child_count_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + ofnode node, child_node; + u32 val; + + node = oftree_path(otree, "/node"); + ut_assert(ofnode_valid(node)); + + val = ofnode_get_child_count(node); + ut_asserteq(2, val); + + child_node = ofnode_first_subnode(node); + ut_assert(ofnode_valid(child_node)); + val = ofnode_get_child_count(child_node); + ut_asserteq(0, val); + + return 0; +} +DM_TEST(dm_test_ofnode_get_child_count_ot, UT_TESTF_OTHER_FDT); + static int dm_test_ofnode_is_enabled(struct unit_test_state *uts) { ofnode root_node = ofnode_path("/"); @@ -267,6 +466,19 @@ static int dm_test_ofnode_is_enabled(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_is_enabled, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +static int dm_test_ofnode_is_enabled_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + ofnode root_node = oftree_root(otree); + ofnode node = oftree_path(otree, "/target"); + + ut_assert(ofnode_is_enabled(root_node)); + ut_assert(!ofnode_is_enabled(node)); + + return 0; +} +DM_TEST(dm_test_ofnode_is_enabled_ot, UT_TESTF_OTHER_FDT); + static int dm_test_ofnode_get_reg(struct unit_test_state *uts) { ofnode node; @@ -303,27 +515,59 @@ static int dm_test_ofnode_get_reg(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_get_reg, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +static int dm_test_ofnode_get_reg_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + ofnode node = oftree_path(otree, "/target"); + fdt_addr_t addr; + + addr = ofnode_get_addr(node); + ut_asserteq(0x8000, addr); + + return 0; +} +DM_TEST(dm_test_ofnode_get_reg_ot, UT_TESTF_OTHER_FDT); + static int dm_test_ofnode_get_path(struct unit_test_state *uts) { const char *path = "/translation-test@8000/noxlatebus@3,300/dev@42"; char buf[64]; ofnode node; - int res; node = ofnode_path(path); ut_assert(ofnode_valid(node)); - res = ofnode_get_path(node, buf, 64); - ut_asserteq(0, res); + ut_assertok(ofnode_get_path(node, buf, sizeof(buf))); ut_asserteq_str(path, buf); - res = ofnode_get_path(node, buf, 32); - ut_asserteq(-ENOSPC, res); + ut_asserteq(-ENOSPC, ofnode_get_path(node, buf, 32)); + + ut_assertok(ofnode_get_path(ofnode_root(), buf, 32)); + ut_asserteq_str("/", buf); return 0; } DM_TEST(dm_test_ofnode_get_path, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +static int dm_test_ofnode_get_path_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + const char *path = "/node/subnode"; + ofnode node = oftree_path(otree, path); + char buf[64]; + + ut_assert(ofnode_valid(node)); + + ut_assertok(ofnode_get_path(node, buf, sizeof(buf))); + ut_asserteq_str(path, buf); + + ut_assertok(ofnode_get_path(oftree_root(otree), buf, 32)); + ut_asserteq_str("/", buf); + + return 0; +} +DM_TEST(dm_test_ofnode_get_path_ot, UT_TESTF_OTHER_FDT); + static int dm_test_ofnode_conf(struct unit_test_state *uts) { ut_assert(!ofnode_conf_read_bool("missing")); @@ -483,13 +727,17 @@ DM_TEST(dm_test_ofnode_get_phy, 0); * @uts: Test state * @fdt: Place to write FDT * @size: Maximum size of space for fdt + * @id: id value to add to the tree ('id' property in root node) */ -static int make_ofnode_fdt(struct unit_test_state *uts, void *fdt, int size) +static int make_ofnode_fdt(struct unit_test_state *uts, void *fdt, int size, + int id) { ut_assertok(fdt_create(fdt, size)); ut_assertok(fdt_finish_reservemap(fdt)); ut_assert(fdt_begin_node(fdt, "") >= 0); + ut_assertok(fdt_property_u32(fdt, "id", id)); + ut_assert(fdt_begin_node(fdt, "aliases") >= 0); ut_assertok(fdt_property_string(fdt, "mmc0", "/new-mmc")); ut_assertok(fdt_end_node(fdt)); @@ -505,37 +753,41 @@ static int make_ofnode_fdt(struct unit_test_state *uts, void *fdt, int size) static int dm_test_ofnode_root(struct unit_test_state *uts) { - struct device_node *root = NULL; char fdt[256]; oftree tree; ofnode node; + int ret; /* Check that aliases work on the control FDT */ node = ofnode_get_aliases_node("ethernet3"); ut_assert(ofnode_valid(node)); ut_asserteq_str("sbe5", ofnode_get_name(node)); - ut_assertok(make_ofnode_fdt(uts, fdt, sizeof(fdt))); - if (of_live_active()) { - ut_assertok(unflatten_device_tree(fdt, &root)); - tree.np = root; - } else { - tree.fdt = fdt; - } + ut_assert(!oftree_valid(oftree_null())); + + ut_assertok(make_ofnode_fdt(uts, fdt, sizeof(fdt), 0)); + ret = get_oftree(uts, fdt, &tree); + + /* skip the rest of this test if multiple FDTs are not supported */ + if (ret == -EOVERFLOW) + return 0; + + ut_assertok(ret); + ut_assert(oftree_valid(tree)); /* Make sure they don't work on this new tree */ - node = ofnode_path_root(tree, "mmc0"); + node = oftree_path(tree, "mmc0"); ut_assert(!ofnode_valid(node)); /* It should appear in the new tree */ - node = ofnode_path_root(tree, "/new-mmc"); + node = oftree_path(tree, "/new-mmc"); ut_assert(ofnode_valid(node)); /* ...and not in the control FDT */ - node = ofnode_path_root(oftree_default(), "/new-mmc"); + node = oftree_path(oftree_default(), "/new-mmc"); ut_assert(!ofnode_valid(node)); - free(root); + free_oftree(tree); return 0; } @@ -570,7 +822,8 @@ static int dm_test_ofnode_livetree_writing(struct unit_test_state *uts) ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr(dev)); /* reg = 0x42, size = 0x100 */ ut_assertok(ofnode_write_prop(node, "reg", - "\x00\x00\x00\x42\x00\x00\x01\x00", 8)); + "\x00\x00\x00\x42\x00\x00\x01\x00", 8, + false)); ut_asserteq(0x42, dev_read_addr(dev)); /* Test disabling devices */ @@ -584,11 +837,71 @@ static int dm_test_ofnode_livetree_writing(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_ofnode_livetree_writing, - UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT | UT_TESTF_LIVE_OR_FLAT); + UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int check_write_prop(struct unit_test_state *uts, ofnode node) +{ + char prop[] = "middle-name"; + char name[10]; + int len; + + strcpy(name, "cecil"); + len = strlen(name) + 1; + ut_assertok(ofnode_write_prop(node, prop, name, len, false)); + ut_asserteq_str(name, ofnode_read_string(node, prop)); + + /* change the underlying value, this should mess up the live tree */ + strcpy(name, "tony"); + if (of_live_active()) { + ut_asserteq_str(name, ofnode_read_string(node, prop)); + } else { + ut_asserteq_str("cecil", ofnode_read_string(node, prop)); + } + + /* try again, this time copying the property */ + strcpy(name, "mary"); + ut_assertok(ofnode_write_prop(node, prop, name, len, true)); + ut_asserteq_str(name, ofnode_read_string(node, prop)); + strcpy(name, "leah"); + + /* both flattree and livetree behave the same */ + ut_asserteq_str("mary", ofnode_read_string(node, prop)); + + return 0; +} + +/* writing the tree with and without copying the property */ +static int dm_test_ofnode_write_copy(struct unit_test_state *uts) +{ + ofnode node; + + node = ofnode_path("/a-test"); + ut_assertok(check_write_prop(uts, node)); + + return 0; +} +DM_TEST(dm_test_ofnode_write_copy, UT_TESTF_SCAN_FDT); + +static int dm_test_ofnode_write_copy_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + ofnode node, check_node; + + node = oftree_path(otree, "/node"); + ut_assertok(check_write_prop(uts, node)); + + /* make sure the control FDT is not touched */ + check_node = ofnode_path("/node"); + ut_assertnull(ofnode_read_string(check_node, "middle-name")); + + return 0; +} +DM_TEST(dm_test_ofnode_write_copy_ot, UT_TESTF_OTHER_FDT); static int dm_test_ofnode_u32(struct unit_test_state *uts) { ofnode node; + u32 val; node = ofnode_path("/lcd"); ut_assert(ofnode_valid(node)); @@ -597,7 +910,328 @@ static int dm_test_ofnode_u32(struct unit_test_state *uts) ut_asserteq(1367, ofnode_read_u32_default(node, "xres", 123)); ut_assertok(ofnode_write_u32(node, "xres", 1366)); + node = ofnode_path("/backlight"); + ut_assertok(ofnode_read_u32_index(node, "brightness-levels", 0, &val)); + ut_asserteq(0, val); + ut_assertok(ofnode_read_u32_index(node, "brightness-levels", 1, &val)); + ut_asserteq(16, val); + ut_assertok(ofnode_read_u32_index(node, "brightness-levels", 8, &val)); + ut_asserteq(255, val); + ut_asserteq(-EOVERFLOW, + ofnode_read_u32_index(node, "brightness-levels", 9, &val)); + ut_asserteq(-EINVAL, ofnode_read_u32_index(node, "missing", 0, &val)); + + return 0; +} +DM_TEST(dm_test_ofnode_u32, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int dm_test_ofnode_u32_array(struct unit_test_state *uts) +{ + ofnode node; + u32 val[10]; + + node = ofnode_path("/a-test"); + ut_assert(ofnode_valid(node)); + ut_assertok(ofnode_read_u32_array(node, "int-value", val, 1)); + ut_asserteq(-EINVAL, ofnode_read_u32_array(node, "missing", val, 1)); + ut_asserteq(-EOVERFLOW, ofnode_read_u32_array(node, "bool-value", val, + 1)); + + memset(val, '\0', sizeof(val)); + ut_assertok(ofnode_read_u32_array(node, "int-array", val + 1, 3)); + ut_asserteq(0, val[0]); + ut_asserteq(5678, val[1]); + ut_asserteq(9123, val[2]); + ut_asserteq(4567, val[3]); + ut_asserteq(0, val[4]); + ut_asserteq(-EOVERFLOW, ofnode_read_u32_array(node, "int-array", val, + 4)); + + return 0; +} +DM_TEST(dm_test_ofnode_u32_array, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int dm_test_ofnode_u64(struct unit_test_state *uts) +{ + ofnode node; + u64 val; + + node = ofnode_path("/a-test"); + ut_assert(ofnode_valid(node)); + ut_assertok(ofnode_read_u64(node, "int64-value", &val)); + ut_asserteq_64(0x1111222233334444, val); + ut_asserteq(-EINVAL, ofnode_read_u64(node, "missing", &val)); + + return 0; +} +DM_TEST(dm_test_ofnode_u64, UT_TESTF_SCAN_FDT); + +static int dm_test_ofnode_add_subnode(struct unit_test_state *uts) +{ + ofnode node, check, subnode; + char buf[128]; + + node = ofnode_path("/lcd"); + ut_assert(ofnode_valid(node)); + ut_assertok(ofnode_add_subnode(node, "edmund", &subnode)); + check = ofnode_path("/lcd/edmund"); + ut_asserteq(subnode.of_offset, check.of_offset); + ut_assertok(ofnode_get_path(subnode, buf, sizeof(buf))); + ut_asserteq_str("/lcd/edmund", buf); + + if (of_live_active()) { + struct device_node *child; + + ut_assertok(of_add_subnode((void *)ofnode_to_np(node), "edmund", + 2, &child)); + ut_asserteq_str("ed", child->name); + ut_asserteq_str("/lcd/ed", child->full_name); + check = ofnode_path("/lcd/ed"); + ut_asserteq_ptr(child, check.np); + ut_assertok(ofnode_get_path(np_to_ofnode(child), buf, + sizeof(buf))); + ut_asserteq_str("/lcd/ed", buf); + } + + /* An existing node should be returned with -EEXIST */ + ut_asserteq(-EEXIST, ofnode_add_subnode(node, "edmund", &check)); + ut_asserteq(subnode.of_offset, check.of_offset); + + /* add a root node */ + node = ofnode_path("/"); + ut_assert(ofnode_valid(node)); + ut_assertok(ofnode_add_subnode(node, "lcd2", &subnode)); + check = ofnode_path("/lcd2"); + ut_asserteq(subnode.of_offset, check.of_offset); + ut_assertok(ofnode_get_path(subnode, buf, sizeof(buf))); + ut_asserteq_str("/lcd2", buf); + + if (of_live_active()) { + ulong start; + int i; + + /* + * Make sure each of the three malloc()checks in + * of_add_subnode() work + */ + for (i = 0; i < 3; i++) { + malloc_enable_testing(i); + start = ut_check_free(); + ut_asserteq(-ENOMEM, ofnode_add_subnode(node, "anthony", + &check)); + ut_assertok(ut_check_delta(start)); + } + + /* This should pass since we allow 3 allocations */ + malloc_enable_testing(3); + ut_assertok(ofnode_add_subnode(node, "anthony", &check)); + malloc_disable_testing(); + } + + /* write to the empty node */ + ut_assertok(ofnode_write_string(subnode, "example", "text")); + + return 0; +} +DM_TEST(dm_test_ofnode_add_subnode, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int dm_test_ofnode_for_each_prop(struct unit_test_state *uts) +{ + ofnode node, subnode; + struct ofprop prop; + int count; + + node = ofnode_path("/buttons"); + count = 0; + + /* we expect "compatible" for each node */ + ofnode_for_each_prop(prop, node) + count++; + ut_asserteq(1, count); + + /* there are two nodes, each with 2 properties */ + ofnode_for_each_subnode(subnode, node) + ofnode_for_each_prop(prop, subnode) + count++; + ut_asserteq(5, count); + + return 0; +} +DM_TEST(dm_test_ofnode_for_each_prop, UT_TESTF_SCAN_FDT); + +static int dm_test_ofnode_by_compatible(struct unit_test_state *uts) +{ + const char *compat = "denx,u-boot-fdt-test"; + ofnode node; + int count; + + count = 0; + for (node = ofnode_null(); + node = ofnode_by_compatible(node, compat), ofnode_valid(node);) + count++; + ut_asserteq(11, count); + + return 0; +} +DM_TEST(dm_test_ofnode_by_compatible, UT_TESTF_SCAN_FDT); + +static int dm_test_ofnode_by_compatible_ot(struct unit_test_state *uts) +{ + const char *compat = "sandbox-other2"; + oftree otree = get_other_oftree(uts); + ofnode node; + int count; + + count = 0; + for (node = oftree_root(otree); + node = ofnode_by_compatible(node, compat), ofnode_valid(node);) + count++; + ut_asserteq(2, count); + + return 0; +} +DM_TEST(dm_test_ofnode_by_compatible_ot, UT_TESTF_OTHER_FDT); + +static int dm_test_ofnode_find_subnode(struct unit_test_state *uts) +{ + ofnode node, subnode; + + node = ofnode_path("/buttons"); + + subnode = ofnode_find_subnode(node, "btn1"); + ut_assert(ofnode_valid(subnode)); + ut_asserteq_str("btn1", ofnode_get_name(subnode)); + + subnode = ofnode_find_subnode(node, "btn"); + ut_assert(!ofnode_valid(subnode)); + + return 0; +} +DM_TEST(dm_test_ofnode_find_subnode, UT_TESTF_SCAN_FDT); + +static int dm_test_ofnode_find_subnode_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + ofnode node, subnode; + + node = oftree_path(otree, "/node"); + + subnode = ofnode_find_subnode(node, "subnode"); + ut_assert(ofnode_valid(subnode)); + ut_asserteq_str("subnode", ofnode_get_name(subnode)); + + subnode = ofnode_find_subnode(node, "btn"); + ut_assert(!ofnode_valid(subnode)); + + return 0; +} +DM_TEST(dm_test_ofnode_find_subnode_ot, UT_TESTF_OTHER_FDT); + +static int dm_test_ofnode_get_name(struct unit_test_state *uts) +{ + ofnode node; + + node = ofnode_path("/buttons"); + ut_assert(ofnode_valid(node)); + ut_asserteq_str("buttons", ofnode_get_name(node)); + ut_asserteq_str("", ofnode_get_name(ofnode_root())); + + return 0; +} +DM_TEST(dm_test_ofnode_get_name, UT_TESTF_SCAN_FDT); + +/* try to access more FDTs than is supported */ +static int dm_test_ofnode_too_many(struct unit_test_state *uts) +{ + const int max_trees = CONFIG_IS_ENABLED(OFNODE_MULTI_TREE, + (CONFIG_OFNODE_MULTI_TREE_MAX), (1)); + const int fdt_size = 256; + const int num_trees = max_trees + 1; + char fdt[num_trees][fdt_size]; + int i; + + for (i = 0; i < num_trees; i++) { + oftree tree; + int ret; + + ut_assertok(make_ofnode_fdt(uts, fdt[i], fdt_size, i)); + ret = get_oftree(uts, fdt[i], &tree); + + /* + * With flat tree we have the control FDT using one slot. Live + * tree has no limit since it uses pointers, not integer tree + * IDs + */ + if (of_live_active() || i < max_trees - 1) { + ut_assertok(ret); + } else { + /* + * tree should be invalid when we try to register too + * many trees + */ + ut_asserteq(-EOVERFLOW, ret); + } + } + + return 0; +} +DM_TEST(dm_test_ofnode_too_many, UT_TESTF_SCAN_FDT); + +static int check_copy_props(struct unit_test_state *uts, ofnode src, + ofnode dst) +{ + u32 reg[2], val; + + ut_assertok(ofnode_copy_props(src, dst)); + + ut_assertok(ofnode_read_u32(dst, "ping-expect", &val)); + ut_asserteq(3, val); + + ut_asserteq_str("denx,u-boot-fdt-test", + ofnode_read_string(dst, "compatible")); + + /* check that a property with the same name is overwritten */ + ut_assertok(ofnode_read_u32_array(dst, "reg", reg, ARRAY_SIZE(reg))); + ut_asserteq(3, reg[0]); + ut_asserteq(1, reg[1]); + + /* reset the compatible so the live tree does not change */ + ut_assertok(ofnode_write_string(dst, "compatible", "nothing")); + + return 0; +} + +static int dm_test_ofnode_copy_props(struct unit_test_state *uts) +{ + ofnode src, dst; + + /* + * These nodes are chosen so that the src node is before the destination + * node in the tree. This doesn't matter with livetree, but with + * flattree any attempt to insert a property earlier in the tree will + * mess up the offsets after it. + */ + src = ofnode_path("/b-test"); + dst = ofnode_path("/some-bus"); + + ut_assertok(check_copy_props(uts, src, dst)); + + /* check a property that is in the destination already */ + ut_asserteq_str("mux0", ofnode_read_string(dst, "mux-control-names")); + + return 0; +} +DM_TEST(dm_test_ofnode_copy_props, UT_TESTF_SCAN_FDT); + +static int dm_test_ofnode_copy_props_ot(struct unit_test_state *uts) +{ + ofnode src, dst; + oftree otree = get_other_oftree(uts); + + src = ofnode_path("/b-test"); + dst = oftree_path(otree, "/node/subnode2"); + ut_assertok(check_copy_props(uts, src, dst)); + return 0; } -DM_TEST(dm_test_ofnode_u32, - UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT | UT_TESTF_LIVE_OR_FLAT); +DM_TEST(dm_test_ofnode_copy_props_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); diff --git a/test/dm/ofread.c b/test/dm/ofread.c index 8c7dd825136..3523860d2b3 100644 --- a/test/dm/ofread.c +++ b/test/dm/ofread.c @@ -5,7 +5,7 @@ #include <dm/test.h> #include <test/ut.h> -static int dm_test_ofnode_get_property_by_prop(struct unit_test_state *uts) +static int dm_test_ofprop_get_property(struct unit_test_state *uts) { ofnode node; struct ofprop prop; @@ -14,10 +14,10 @@ static int dm_test_ofnode_get_property_by_prop(struct unit_test_state *uts) int res, len, count = 0; node = ofnode_path("/cros-ec/flash"); - for (res = ofnode_get_first_property(node, &prop); + for (res = ofnode_first_property(node, &prop); !res; - res = ofnode_get_next_property(&prop)) { - value = ofnode_get_property_by_prop(&prop, &propname, &len); + res = ofnode_next_property(&prop)) { + value = ofprop_get_property(&prop, &propname, &len); ut_assertnonnull(value); switch (count) { case 0: @@ -46,5 +46,4 @@ static int dm_test_ofnode_get_property_by_prop(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_get_property_by_prop, - UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +DM_TEST(dm_test_ofprop_get_property, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); diff --git a/test/image/spl_load.c b/test/image/spl_load.c index df389e26f90..4e27ff460ab 100644 --- a/test/image/spl_load.c +++ b/test/image/spl_load.c @@ -49,7 +49,7 @@ int board_fit_config_name_match(const char *name) return 0; } -struct image_header *spl_get_load_buffer(ssize_t offset, size_t size) +struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size) { return map_sysmem(0x100000, 0); } @@ -57,7 +57,7 @@ struct image_header *spl_get_load_buffer(ssize_t offset, size_t size) static int spl_test_load(struct unit_test_state *uts) { struct spl_image_info image; - struct image_header *header; + struct legacy_img_hdr *header; struct text_ctx text_ctx; struct spl_load_info load; char fname[256]; diff --git a/test/test-main.c b/test/test-main.c index ae34002a3d4..d74df297c43 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -9,14 +9,53 @@ #include <cyclic.h> #include <dm.h> #include <event.h> +#include <of_live.h> +#include <os.h> +#include <dm/ofnode.h> #include <dm/root.h> #include <dm/test.h> #include <dm/uclass-internal.h> #include <test/test.h> #include <test/ut.h> +#include <u-boot/crc.h> DECLARE_GLOBAL_DATA_PTR; +/** + * enum fdtchk_t - what to do with the device tree (gd->fdt_blob) + * + * This affects what happens with the device tree before and after a test + * + * @FDTCHK_NONE: Do nothing + * @FDTCHK_CHECKSUM: Take a checksum of the FDT before the test runs and + * compare it afterwards to detect any changes + * @FDTCHK_COPY: Make a copy of the FDT and restore it afterwards + */ +enum fdtchk_t { + FDTCHK_NONE, + FDTCHK_CHECKSUM, + FDTCHK_COPY, +}; + +/** + * fdt_action() - get the required action for the FDT + * + * @return the action that should be taken for this build + */ +static enum fdtchk_t fdt_action(void) +{ + /* Do a copy for sandbox (but only the U-Boot build, not SPL) */ + if (CONFIG_IS_ENABLED(SANDBOX)) + return FDTCHK_COPY; + + /* For sandbox SPL builds, do nothing */ + if (IS_ENABLED(CONFIG_SANDBOX)) + return FDTCHK_NONE; + + /* For all other boards, do a checksum */ + return FDTCHK_CHECKSUM; +} + /* This is valid when a test is running, NULL otherwise */ static struct unit_test_state *cur_test_state; @@ -42,17 +81,26 @@ static int dm_test_pre_run(struct unit_test_state *uts) { bool of_live = uts->of_live; + if (of_live && (gd->flags & GD_FLG_FDT_CHANGED)) { + printf("Cannot run live tree test as device tree changed\n"); + return -EFAULT; + } uts->root = NULL; uts->testdev = NULL; uts->force_fail_alloc = false; uts->skip_post_probe = false; + if (fdt_action() == FDTCHK_CHECKSUM) + uts->fdt_chksum = crc8(0, gd->fdt_blob, + fdt_totalsize(gd->fdt_blob)); gd->dm_root = NULL; + malloc_disable_testing(); if (CONFIG_IS_ENABLED(UT_DM) && !CONFIG_IS_ENABLED(OF_PLATDATA)) memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); arch_reset_for_test(); /* Determine whether to make the live tree available */ gd_set_of_root(of_live ? uts->of_root : NULL); + oftree_reset(); ut_assertok(dm_init(of_live)); uts->root = dm_root(); @@ -63,6 +111,33 @@ static int dm_test_post_run(struct unit_test_state *uts) { int id; + if (gd->fdt_blob) { + switch (fdt_action()) { + case FDTCHK_COPY: + memcpy((void *)gd->fdt_blob, uts->fdt_copy, uts->fdt_size); + break; + case FDTCHK_CHECKSUM: { + uint chksum; + + chksum = crc8(0, gd->fdt_blob, fdt_totalsize(gd->fdt_blob)); + if (chksum != uts->fdt_chksum) { + /* + * We cannot run any more tests that need the + * live tree, since its strings point into the + * flat tree, which has changed. This likely + * means that at least some of the pointers from + * the live tree point to different things + */ + printf("Device tree changed: cannot run live tree tests\n"); + gd->flags |= GD_FLG_FDT_CHANGED; + } + break; + } + case FDTCHK_NONE: + break; + } + } + /* * With of-platdata-inst the uclasses are created at build time. If we * destroy them we cannot get them back since uclass_add() is not @@ -242,6 +317,20 @@ static int test_pre_run(struct unit_test_state *uts, struct unit_test *test) (test->flags & UT_TESTF_SCAN_FDT)) ut_assertok(dm_extended_scan(false)); + if (IS_ENABLED(CONFIG_SANDBOX) && (test->flags & UT_TESTF_OTHER_FDT)) { + /* make sure the other FDT is available */ + ut_assertok(test_load_other_fdt(uts)); + + /* + * create a new live tree with it for every test, in case a + * test modifies the tree + */ + if (of_live_active()) { + ut_assertok(unflatten_device_tree(uts->other_fdt, + &uts->of_other)); + } + } + if (test->flags & UT_TESTF_CONSOLE_REC) { int ret = console_record_reset_enable(); @@ -270,6 +359,9 @@ static int test_post_run(struct unit_test_state *uts, struct unit_test *test) ut_assertok(cyclic_uninit()); ut_assertok(event_uninit()); + free(uts->of_other); + uts->of_other = NULL; + return 0; } @@ -340,11 +432,13 @@ static int ut_run_test_live_flat(struct unit_test_state *uts, { int runs; + if ((test->flags & UT_TESTF_OTHER_FDT) && !IS_ENABLED(CONFIG_SANDBOX)) + return -EAGAIN; + /* Run with the live tree if possible */ runs = 0; if (CONFIG_IS_ENABLED(OF_LIVE)) { - if (!(test->flags & - (UT_TESTF_FLAT_TREE | UT_TESTF_LIVE_OR_FLAT))) { + if (!(test->flags & UT_TESTF_FLAT_TREE)) { uts->of_live = true; ut_assertok(ut_run_test(uts, test, test->name)); runs++; @@ -352,11 +446,22 @@ static int ut_run_test_live_flat(struct unit_test_state *uts, } /* - * Run with the flat tree if we couldn't run it with live tree, - * or it is a core test. + * Run with the flat tree if: + * - it is not marked for live tree only + * - it doesn't require the 'other' FDT when OFNODE_MULTI_TREE_MAX is + * not enabled (since flat tree can only support a single FDT in that + * case + * - we couldn't run it with live tree, + * - it is a core test (dm tests except video) + * - the FDT is still valid and has not been updated by an earlier test + * (for sandbox we handle this by copying the tree, but not for other + * boards) */ if (!(test->flags & UT_TESTF_LIVE_TREE) && - (!runs || ut_test_run_on_flattree(test))) { + (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || + !(test->flags & UT_TESTF_OTHER_FDT)) && + (!runs || ut_test_run_on_flattree(test)) && + !(gd->flags & GD_FLG_FDT_CHANGED)) { uts->of_live = false; ut_assertok(ut_run_test(uts, test, test->name)); runs++; @@ -443,8 +548,25 @@ int ut_run_list(const char *category, const char *prefix, uts.of_root = gd_of_root(); uts.runs_per_test = runs_per_test; + if (fdt_action() == FDTCHK_COPY && gd->fdt_blob) { + uts.fdt_size = fdt_totalsize(gd->fdt_blob); + uts.fdt_copy = os_malloc(uts.fdt_size); + if (!uts.fdt_copy) { + printf("Out of memory for device tree copy\n"); + return -ENOMEM; + } + memcpy(uts.fdt_copy, gd->fdt_blob, uts.fdt_size); + } ret = ut_run_tests(&uts, prefix, tests, count, select_name); + /* Best efforts only...ignore errors */ + if (has_dm_tests) + dm_test_restore(uts.of_root); + if (IS_ENABLED(CONFIG_SANDBOX)) { + os_free(uts.fdt_copy); + os_free(uts.other_fdt); + } + if (ret == -ENOENT) printf("Test '%s' not found\n", select_name); else |