aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Rowand <frank.rowand@sony.com>2018-02-12 03:19:42 -0500
committerFrank Rowand <frowand.list@gmail.com>2018-03-04 03:29:24 -0500
commit39a751a4cb7e4798f0ce1169ec92de4a1aae39e3 (patch)
tree6946dd93cc2f4bdbe1a3c1b6ae64aa6b566be114
parent581e929018ce078d0ce0b02780de2f61e858903b (diff)
of: change overlay apply input data from unflattened to FDT
Move duplicating and unflattening of an overlay flattened devicetree (FDT) into the overlay application code. To accomplish this, of_overlay_apply() is replaced by of_overlay_fdt_apply(). The copy of the FDT (aka "duplicate FDT") now belongs to devicetree code, which is thus responsible for freeing the duplicate FDT. The caller of of_overlay_fdt_apply() remains responsible for freeing the original FDT. The unflattened devicetree now belongs to devicetree code, which is thus responsible for freeing the unflattened devicetree. These ownership changes prevent early freeing of the duplicated FDT or the unflattened devicetree, which could result in use after free errors. of_overlay_fdt_apply() is a private function for the anticipated overlay loader. Update unittest.c to use of_overlay_fdt_apply() instead of of_overlay_apply(). Move overlay fragments from artificial locations in drivers/of/unittest-data/tests-overlay.dtsi into one devicetree source file per overlay. This led to changes in drivers/of/unitest-data/Makefile and drivers/of/unitest.c. - Add overlay directives to the overlay devicetree source files so that dtc will compile them as true overlays into one FDT data chunk per overlay. - Set CFLAGS for drivers/of/unittest-data/testcases.dts so that symbols will be generated for overlay resolution of overlays that are no longer artificially contained in testcases.dts - Unflatten and apply each unittest overlay FDT using of_overlay_fdt_apply(). - Enable the of_resolve_phandles() check for whether the unflattened overlay is detached. This check was previously disabled because the overlays from tests-overlay.dtsi were not unflattened into detached trees. - Other changes to unittest.c infrastructure to manage multiple test FDTs built into the kernel image (access by name instead of arbitrary number). - of_unittest_overlay_high_level(): previously unused code to add properties from the overlay_base devicetree to the live tree was triggered by the restructuring of tests-overlay.dtsi and thus testcases.dts. This exposed two bugs: (1) the need to dup a property before adding it, and (2) property 'name' is auto-generated in the unflatten code and thus will be a duplicate in the __symbols__ node - do not treat this duplicate as an error. Signed-off-by: Frank Rowand <frank.rowand@sony.com>
-rw-r--r--drivers/of/Kconfig1
-rw-r--r--drivers/of/overlay.c112
-rw-r--r--drivers/of/resolver.c6
-rw-r--r--drivers/of/unittest-data/Makefile28
-rw-r--r--drivers/of/unittest-data/overlay_0.dts14
-rw-r--r--drivers/of/unittest-data/overlay_1.dts14
-rw-r--r--drivers/of/unittest-data/overlay_10.dts34
-rw-r--r--drivers/of/unittest-data/overlay_11.dts34
-rw-r--r--drivers/of/unittest-data/overlay_12.dts14
-rw-r--r--drivers/of/unittest-data/overlay_13.dts14
-rw-r--r--drivers/of/unittest-data/overlay_15.dts35
-rw-r--r--drivers/of/unittest-data/overlay_2.dts14
-rw-r--r--drivers/of/unittest-data/overlay_3.dts14
-rw-r--r--drivers/of/unittest-data/overlay_4.dts23
-rw-r--r--drivers/of/unittest-data/overlay_5.dts14
-rw-r--r--drivers/of/unittest-data/overlay_6.dts15
-rw-r--r--drivers/of/unittest-data/overlay_7.dts15
-rw-r--r--drivers/of/unittest-data/overlay_8.dts15
-rw-r--r--drivers/of/unittest-data/overlay_9.dts15
-rw-r--r--drivers/of/unittest-data/tests-overlay.dtsi213
-rw-r--r--drivers/of/unittest.c300
-rw-r--r--include/linux/of.h6
22 files changed, 562 insertions, 388 deletions
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 783e0870bd22..ad3fcad4d75b 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -92,6 +92,7 @@ config OF_RESOLVE
92config OF_OVERLAY 92config OF_OVERLAY
93 bool "Device Tree overlays" 93 bool "Device Tree overlays"
94 select OF_DYNAMIC 94 select OF_DYNAMIC
95 select OF_FLATTREE
95 select OF_RESOLVE 96 select OF_RESOLVE
96 help 97 help
97 Overlays are a method to dynamically modify part of the kernel's 98 Overlays are a method to dynamically modify part of the kernel's
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 3397d7642958..e3d7f69a8333 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -12,10 +12,12 @@
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/of.h> 13#include <linux/of.h>
14#include <linux/of_device.h> 14#include <linux/of_device.h>
15#include <linux/of_fdt.h>
15#include <linux/string.h> 16#include <linux/string.h>
16#include <linux/ctype.h> 17#include <linux/ctype.h>
17#include <linux/errno.h> 18#include <linux/errno.h>
18#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/libfdt.h>
19#include <linux/err.h> 21#include <linux/err.h>
20#include <linux/idr.h> 22#include <linux/idr.h>
21 23
@@ -33,7 +35,9 @@ struct fragment {
33 35
34/** 36/**
35 * struct overlay_changeset 37 * struct overlay_changeset
38 * @id: changeset identifier
36 * @ovcs_list: list on which we are located 39 * @ovcs_list: list on which we are located
40 * @fdt: FDT that was unflattened to create @overlay_tree
37 * @overlay_tree: expanded device tree that contains the fragment nodes 41 * @overlay_tree: expanded device tree that contains the fragment nodes
38 * @count: count of fragment structures 42 * @count: count of fragment structures
39 * @fragments: fragment nodes in the overlay expanded device tree 43 * @fragments: fragment nodes in the overlay expanded device tree
@@ -43,6 +47,7 @@ struct fragment {
43struct overlay_changeset { 47struct overlay_changeset {
44 int id; 48 int id;
45 struct list_head ovcs_list; 49 struct list_head ovcs_list;
50 const void *fdt;
46 struct device_node *overlay_tree; 51 struct device_node *overlay_tree;
47 int count; 52 int count;
48 struct fragment *fragments; 53 struct fragment *fragments;
@@ -503,7 +508,8 @@ static struct device_node *find_target_node(struct device_node *info_node)
503 508
504/** 509/**
505 * init_overlay_changeset() - initialize overlay changeset from overlay tree 510 * init_overlay_changeset() - initialize overlay changeset from overlay tree
506 * @ovcs Overlay changeset to build 511 * @ovcs: Overlay changeset to build
512 * @fdt: the FDT that was unflattened to create @tree
507 * @tree: Contains all the overlay fragments and overlay fixup nodes 513 * @tree: Contains all the overlay fragments and overlay fixup nodes
508 * 514 *
509 * Initialize @ovcs. Populate @ovcs->fragments with node information from 515 * Initialize @ovcs. Populate @ovcs->fragments with node information from
@@ -514,7 +520,7 @@ static struct device_node *find_target_node(struct device_node *info_node)
514 * detected in @tree, or -ENOSPC if idr_alloc() error. 520 * detected in @tree, or -ENOSPC if idr_alloc() error.
515 */ 521 */
516static int init_overlay_changeset(struct overlay_changeset *ovcs, 522static int init_overlay_changeset(struct overlay_changeset *ovcs,
517 struct device_node *tree) 523 const void *fdt, struct device_node *tree)
518{ 524{
519 struct device_node *node, *overlay_node; 525 struct device_node *node, *overlay_node;
520 struct fragment *fragment; 526 struct fragment *fragment;
@@ -535,6 +541,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
535 pr_debug("%s() tree is not root\n", __func__); 541 pr_debug("%s() tree is not root\n", __func__);
536 542
537 ovcs->overlay_tree = tree; 543 ovcs->overlay_tree = tree;
544 ovcs->fdt = fdt;
538 545
539 INIT_LIST_HEAD(&ovcs->ovcs_list); 546 INIT_LIST_HEAD(&ovcs->ovcs_list);
540 547
@@ -606,6 +613,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
606 } 613 }
607 614
608 if (!cnt) { 615 if (!cnt) {
616 pr_err("no fragments or symbols in overlay\n");
609 ret = -EINVAL; 617 ret = -EINVAL;
610 goto err_free_fragments; 618 goto err_free_fragments;
611 } 619 }
@@ -642,11 +650,24 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs)
642 } 650 }
643 kfree(ovcs->fragments); 651 kfree(ovcs->fragments);
644 652
653 /*
654 * TODO
655 *
656 * would like to: kfree(ovcs->overlay_tree);
657 * but can not since drivers may have pointers into this data
658 *
659 * would like to: kfree(ovcs->fdt);
660 * but can not since drivers may have pointers into this data
661 */
662
645 kfree(ovcs); 663 kfree(ovcs);
646} 664}
647 665
648/** 666/*
667 * internal documentation
668 *
649 * of_overlay_apply() - Create and apply an overlay changeset 669 * of_overlay_apply() - Create and apply an overlay changeset
670 * @fdt: the FDT that was unflattened to create @tree
650 * @tree: Expanded overlay device tree 671 * @tree: Expanded overlay device tree
651 * @ovcs_id: Pointer to overlay changeset id 672 * @ovcs_id: Pointer to overlay changeset id
652 * 673 *
@@ -685,21 +706,29 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs)
685 * id is returned to *ovcs_id. 706 * id is returned to *ovcs_id.
686 */ 707 */
687 708
688int of_overlay_apply(struct device_node *tree, int *ovcs_id) 709static int of_overlay_apply(const void *fdt, struct device_node *tree,
710 int *ovcs_id)
689{ 711{
690 struct overlay_changeset *ovcs; 712 struct overlay_changeset *ovcs;
691 int ret = 0, ret_revert, ret_tmp; 713 int ret = 0, ret_revert, ret_tmp;
692 714
693 *ovcs_id = 0; 715 /*
716 * As of this point, fdt and tree belong to the overlay changeset.
717 * overlay changeset code is responsible for freeing them.
718 */
694 719
695 if (devicetree_corrupt()) { 720 if (devicetree_corrupt()) {
696 pr_err("devicetree state suspect, refuse to apply overlay\n"); 721 pr_err("devicetree state suspect, refuse to apply overlay\n");
722 kfree(fdt);
723 kfree(tree);
697 ret = -EBUSY; 724 ret = -EBUSY;
698 goto out; 725 goto out;
699 } 726 }
700 727
701 ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL); 728 ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL);
702 if (!ovcs) { 729 if (!ovcs) {
730 kfree(fdt);
731 kfree(tree);
703 ret = -ENOMEM; 732 ret = -ENOMEM;
704 goto out; 733 goto out;
705 } 734 }
@@ -709,12 +738,17 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id)
709 738
710 ret = of_resolve_phandles(tree); 739 ret = of_resolve_phandles(tree);
711 if (ret) 740 if (ret)
712 goto err_free_overlay_changeset; 741 goto err_free_tree;
713 742
714 ret = init_overlay_changeset(ovcs, tree); 743 ret = init_overlay_changeset(ovcs, fdt, tree);
715 if (ret) 744 if (ret)
716 goto err_free_overlay_changeset; 745 goto err_free_tree;
717 746
747 /*
748 * after overlay_notify(), ovcs->overlay_tree related pointers may have
749 * leaked to drivers, so can not kfree() tree, aka ovcs->overlay_tree;
750 * and can not free fdt, aka ovcs->fdt
751 */
718 ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY); 752 ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY);
719 if (ret) { 753 if (ret) {
720 pr_err("overlay changeset pre-apply notify error %d\n", ret); 754 pr_err("overlay changeset pre-apply notify error %d\n", ret);
@@ -754,6 +788,10 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id)
754 788
755 goto out_unlock; 789 goto out_unlock;
756 790
791err_free_tree:
792 kfree(fdt);
793 kfree(tree);
794
757err_free_overlay_changeset: 795err_free_overlay_changeset:
758 free_overlay_changeset(ovcs); 796 free_overlay_changeset(ovcs);
759 797
@@ -766,7 +804,63 @@ out:
766 804
767 return ret; 805 return ret;
768} 806}
769EXPORT_SYMBOL_GPL(of_overlay_apply); 807
808int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
809 int *ovcs_id)
810{
811 const void *new_fdt;
812 int ret;
813 u32 size;
814 struct device_node *overlay_root;
815
816 *ovcs_id = 0;
817 ret = 0;
818
819 if (overlay_fdt_size < sizeof(struct fdt_header) ||
820 fdt_check_header(overlay_fdt)) {
821 pr_err("Invalid overlay_fdt header\n");
822 return -EINVAL;
823 }
824
825 size = fdt_totalsize(overlay_fdt);
826 if (overlay_fdt_size < size)
827 return -EINVAL;
828
829 /*
830 * Must create permanent copy of FDT because of_fdt_unflatten_tree()
831 * will create pointers to the passed in FDT in the unflattened tree.
832 */
833 new_fdt = kmemdup(overlay_fdt, size, GFP_KERNEL);
834 if (!new_fdt)
835 return -ENOMEM;
836
837 of_fdt_unflatten_tree(new_fdt, NULL, &overlay_root);
838 if (!overlay_root) {
839 pr_err("unable to unflatten overlay_fdt\n");
840 ret = -EINVAL;
841 goto out_free_new_fdt;
842 }
843
844 ret = of_overlay_apply(new_fdt, overlay_root, ovcs_id);
845 if (ret < 0) {
846 /*
847 * new_fdt and overlay_root now belong to the overlay
848 * changeset.
849 * overlay changeset code is responsible for freeing them.
850 */
851 goto out;
852 }
853
854 return 0;
855
856
857out_free_new_fdt:
858 kfree(new_fdt);
859
860out:
861 return ret;
862}
863EXPORT_SYMBOL_GPL(of_overlay_fdt_apply);
770 864
771/* 865/*
772 * Find @np in @tree. 866 * Find @np in @tree.
diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c
index 740d19bde601..b2f645187213 100644
--- a/drivers/of/resolver.c
+++ b/drivers/of/resolver.c
@@ -269,17 +269,11 @@ int of_resolve_phandles(struct device_node *overlay)
269 goto out; 269 goto out;
270 } 270 }
271 271
272#if 0
273 Temporarily disable check so that old style overlay unittests
274 do not fail when of_resolve_phandles() is moved into
275 of_overlay_apply().
276
277 if (!of_node_check_flag(overlay, OF_DETACHED)) { 272 if (!of_node_check_flag(overlay, OF_DETACHED)) {
278 pr_err("overlay not detached\n"); 273 pr_err("overlay not detached\n");
279 err = -EINVAL; 274 err = -EINVAL;
280 goto out; 275 goto out;
281 } 276 }
282#endif
283 277
284 phandle_delta = live_tree_max_phandle() + 1; 278 phandle_delta = live_tree_max_phandle() + 1;
285 adjust_overlay_phandles(overlay, phandle_delta); 279 adjust_overlay_phandles(overlay, phandle_delta);
diff --git a/drivers/of/unittest-data/Makefile b/drivers/of/unittest-data/Makefile
index df697976740a..8fd0ea4b92b0 100644
--- a/drivers/of/unittest-data/Makefile
+++ b/drivers/of/unittest-data/Makefile
@@ -1,8 +1,22 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2DTC_FLAGS_testcases := -Wno-interrupts_property
3obj-y += testcases.dtb.o 2obj-y += testcases.dtb.o
4 3
5obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \ 4obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \
5 overlay_0.dtb.o \
6 overlay_1.dtb.o \
7 overlay_2.dtb.o \
8 overlay_3.dtb.o \
9 overlay_4.dtb.o \
10 overlay_5.dtb.o \
11 overlay_6.dtb.o \
12 overlay_7.dtb.o \
13 overlay_8.dtb.o \
14 overlay_9.dtb.o \
15 overlay_10.dtb.o \
16 overlay_11.dtb.o \
17 overlay_12.dtb.o \
18 overlay_13.dtb.o \
19 overlay_15.dtb.o \
6 overlay_bad_phandle.dtb.o \ 20 overlay_bad_phandle.dtb.o \
7 overlay_bad_symbol.dtb.o \ 21 overlay_bad_symbol.dtb.o \
8 overlay_base.dtb.o 22 overlay_base.dtb.o
@@ -10,10 +24,14 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \
10targets += $(foreach suffix, dtb dtb.S, $(patsubst %.dtb.o,%.$(suffix),$(obj-y))) 24targets += $(foreach suffix, dtb dtb.S, $(patsubst %.dtb.o,%.$(suffix),$(obj-y)))
11 25
12# enable creation of __symbols__ node 26# enable creation of __symbols__ node
13DTC_FLAGS_overlay := -@ 27DTC_FLAGS_overlay += -@
14DTC_FLAGS_overlay_bad_phandle := -@ 28DTC_FLAGS_overlay_bad_phandle += -@
15DTC_FLAGS_overlay_bad_symbol := -@ 29DTC_FLAGS_overlay_bad_symbol += -@
16DTC_FLAGS_overlay_base := -@ 30DTC_FLAGS_overlay_base += -@
31DTC_FLAGS_testcases += -@
32
33# suppress warnings about intentional errors
34DTC_FLAGS_testcases += -Wno-interrupts_property
17 35
18.PRECIOUS: \ 36.PRECIOUS: \
19 $(obj)/%.dtb.S \ 37 $(obj)/%.dtb.S \
diff --git a/drivers/of/unittest-data/overlay_0.dts b/drivers/of/unittest-data/overlay_0.dts
new file mode 100644
index 000000000000..ac0f9e0fe65f
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_0.dts
@@ -0,0 +1,14 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_0 - enable using absolute target path */
7
8 fragment@0 {
9 target-path = "/testcase-data/overlay-node/test-bus/test-unittest0";
10 __overlay__ {
11 status = "okay";
12 };
13 };
14};
diff --git a/drivers/of/unittest-data/overlay_1.dts b/drivers/of/unittest-data/overlay_1.dts
new file mode 100644
index 000000000000..e92a626e2948
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_1.dts
@@ -0,0 +1,14 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_1 - disable using absolute target path */
7
8 fragment@0 {
9 target-path = "/testcase-data/overlay-node/test-bus/test-unittest1";
10 __overlay__ {
11 status = "disabled";
12 };
13 };
14};
diff --git a/drivers/of/unittest-data/overlay_10.dts b/drivers/of/unittest-data/overlay_10.dts
new file mode 100644
index 000000000000..445925a10cd3
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_10.dts
@@ -0,0 +1,34 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_10 */
7 /* overlays 8, 9, 10, 11 application and removal in bad sequence */
8
9 fragment@0 {
10 target-path = "/testcase-data/overlay-node/test-bus";
11 __overlay__ {
12
13 /* suppress DTC warning */
14 #address-cells = <1>;
15 #size-cells = <0>;
16
17 test-unittest10 {
18 compatible = "unittest";
19 status = "okay";
20 reg = <10>;
21
22 #address-cells = <1>;
23 #size-cells = <0>;
24
25 test-unittest101 {
26 compatible = "unittest";
27 status = "okay";
28 reg = <1>;
29 };
30
31 };
32 };
33 };
34};
diff --git a/drivers/of/unittest-data/overlay_11.dts b/drivers/of/unittest-data/overlay_11.dts
new file mode 100644
index 000000000000..c1d14f34359e
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_11.dts
@@ -0,0 +1,34 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_11 */
7 /* overlays 8, 9, 10, 11 application and removal in bad sequence */
8
9 fragment@0 {
10 target-path = "/testcase-data/overlay-node/test-bus";
11 __overlay__ {
12
13 /* suppress DTC warning */
14 #address-cells = <1>;
15 #size-cells = <0>;
16
17 test-unittest11 {
18 compatible = "unittest";
19 status = "okay";
20 reg = <11>;
21
22 #address-cells = <1>;
23 #size-cells = <0>;
24
25 test-unittest111 {
26 compatible = "unittest";
27 status = "okay";
28 reg = <1>;
29 };
30
31 };
32 };
33 };
34};
diff --git a/drivers/of/unittest-data/overlay_12.dts b/drivers/of/unittest-data/overlay_12.dts
new file mode 100644
index 000000000000..ca3441e2cbec
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_12.dts
@@ -0,0 +1,14 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_12 - enable using absolute target path (i2c) */
7
8 fragment@0 {
9 target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12";
10 __overlay__ {
11 status = "okay";
12 };
13 };
14};
diff --git a/drivers/of/unittest-data/overlay_13.dts b/drivers/of/unittest-data/overlay_13.dts
new file mode 100644
index 000000000000..3c30dec63894
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_13.dts
@@ -0,0 +1,14 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_13 - disable using absolute target path (i2c) */
7
8 fragment@0 {
9 target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13";
10 __overlay__ {
11 status = "disabled";
12 };
13 };
14};
diff --git a/drivers/of/unittest-data/overlay_15.dts b/drivers/of/unittest-data/overlay_15.dts
new file mode 100644
index 000000000000..44e44c62b739
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_15.dts
@@ -0,0 +1,35 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_15 - mux overlay */
7
8 fragment@0 {
9 target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus";
10 __overlay__ {
11 #address-cells = <1>;
12 #size-cells = <0>;
13 test-unittest15 {
14 reg = <11>;
15 compatible = "unittest-i2c-mux";
16 status = "okay";
17
18 #address-cells = <1>;
19 #size-cells = <0>;
20
21 i2c@0 {
22 #address-cells = <1>;
23 #size-cells = <0>;
24 reg = <0>;
25
26 test-mux-dev {
27 reg = <32>;
28 compatible = "unittest-i2c-dev";
29 status = "okay";
30 };
31 };
32 };
33 };
34 };
35};
diff --git a/drivers/of/unittest-data/overlay_2.dts b/drivers/of/unittest-data/overlay_2.dts
new file mode 100644
index 000000000000..cf1e4245b7ce
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_2.dts
@@ -0,0 +1,14 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_2 - enable using label */
7
8 fragment@0 {
9 target = <&unittest2>;
10 __overlay__ {
11 status = "okay";
12 };
13 };
14};
diff --git a/drivers/of/unittest-data/overlay_3.dts b/drivers/of/unittest-data/overlay_3.dts
new file mode 100644
index 000000000000..158dc44fc20a
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_3.dts
@@ -0,0 +1,14 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_3 - disable using label */
7
8 fragment@0 {
9 target = <&unittest3>;
10 __overlay__ {
11 status = "disabled";
12 };
13 };
14};
diff --git a/drivers/of/unittest-data/overlay_4.dts b/drivers/of/unittest-data/overlay_4.dts
new file mode 100644
index 000000000000..b4a2e6c6b016
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_4.dts
@@ -0,0 +1,23 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_4 - test insertion of a full node */
7
8 fragment@0 {
9 target = <&unittestbus>;
10 __overlay__ {
11
12 /* suppress DTC warning */
13 #address-cells = <1>;
14 #size-cells = <0>;
15
16 test-unittest4 {
17 compatible = "unittest";
18 status = "okay";
19 reg = <4>;
20 };
21 };
22 };
23};
diff --git a/drivers/of/unittest-data/overlay_5.dts b/drivers/of/unittest-data/overlay_5.dts
new file mode 100644
index 000000000000..02ad25c1f19c
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_5.dts
@@ -0,0 +1,14 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_5 - test overlay apply revert */
7
8 fragment@0 {
9 target-path = "/testcase-data/overlay-node/test-bus/test-unittest5";
10 __overlay__ {
11 status = "okay";
12 };
13 };
14};
diff --git a/drivers/of/unittest-data/overlay_6.dts b/drivers/of/unittest-data/overlay_6.dts
new file mode 100644
index 000000000000..a14e965f5497
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_6.dts
@@ -0,0 +1,15 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_6 */
7 /* overlays 6, 7 application and removal in sequence */
8
9 fragment@0 {
10 target-path = "/testcase-data/overlay-node/test-bus/test-unittest6";
11 __overlay__ {
12 status = "okay";
13 };
14 };
15};
diff --git a/drivers/of/unittest-data/overlay_7.dts b/drivers/of/unittest-data/overlay_7.dts
new file mode 100644
index 000000000000..4bd7e423209c
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_7.dts
@@ -0,0 +1,15 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_7 */
7 /* overlays 6, 7 application and removal in sequence */
8
9 fragment@0 {
10 target-path = "/testcase-data/overlay-node/test-bus/test-unittest7";
11 __overlay__ {
12 status = "okay";
13 };
14 };
15};
diff --git a/drivers/of/unittest-data/overlay_8.dts b/drivers/of/unittest-data/overlay_8.dts
new file mode 100644
index 000000000000..5b21c53945a9
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_8.dts
@@ -0,0 +1,15 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_8 */
7 /* overlays 8, 9, 10, 11 application and removal in bad sequence */
8
9 fragment@0 {
10 target-path = "/testcase-data/overlay-node/test-bus/test-unittest8";
11 __overlay__ {
12 status = "okay";
13 };
14 };
15};
diff --git a/drivers/of/unittest-data/overlay_9.dts b/drivers/of/unittest-data/overlay_9.dts
new file mode 100644
index 000000000000..20ff055a5349
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_9.dts
@@ -0,0 +1,15 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/ {
6 /* overlay_9 */
7 /* overlays 8, 9, 10, 11 application and removal in bad sequence */
8
9 fragment@0 {
10 target-path = "/testcase-data/overlay-node/test-bus/test-unittest8";
11 __overlay__ {
12 property-foo = "bar";
13 };
14 };
15};
diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi
index 7b8001ab9f3a..fa2fb43bccac 100644
--- a/drivers/of/unittest-data/tests-overlay.dtsi
+++ b/drivers/of/unittest-data/tests-overlay.dtsi
@@ -113,218 +113,5 @@
113 }; 113 };
114 }; 114 };
115 }; 115 };
116
117 /* test enable using absolute target path */
118 overlay0 {
119 fragment@0 {
120 target-path = "/testcase-data/overlay-node/test-bus/test-unittest0";
121 __overlay__ {
122 status = "okay";
123 };
124 };
125 };
126
127 /* test disable using absolute target path */
128 overlay1 {
129 fragment@0 {
130 target-path = "/testcase-data/overlay-node/test-bus/test-unittest1";
131 __overlay__ {
132 status = "disabled";
133 };
134 };
135 };
136
137 /* test enable using label */
138 overlay2 {
139 fragment@0 {
140 target = <&unittest2>;
141 __overlay__ {
142 status = "okay";
143 };
144 };
145 };
146
147 /* test disable using label */
148 overlay3 {
149 fragment@0 {
150 target = <&unittest3>;
151 __overlay__ {
152 status = "disabled";
153 };
154 };
155 };
156
157 /* test insertion of a full node */
158 overlay4 {
159 fragment@0 {
160 target = <&unittestbus>;
161 __overlay__ {
162
163 /* suppress DTC warning */
164 #address-cells = <1>;
165 #size-cells = <0>;
166
167 test-unittest4 {
168 compatible = "unittest";
169 status = "okay";
170 reg = <4>;
171 };
172 };
173 };
174 };
175
176 /* test overlay apply revert */
177 overlay5 {
178 fragment@0 {
179 target-path = "/testcase-data/overlay-node/test-bus/test-unittest5";
180 __overlay__ {
181 status = "okay";
182 };
183 };
184 };
185
186 /* test overlays application and removal in sequence */
187 overlay6 {
188 fragment@0 {
189 target-path = "/testcase-data/overlay-node/test-bus/test-unittest6";
190 __overlay__ {
191 status = "okay";
192 };
193 };
194 };
195 overlay7 {
196 fragment@0 {
197 target-path = "/testcase-data/overlay-node/test-bus/test-unittest7";
198 __overlay__ {
199 status = "okay";
200 };
201 };
202 };
203
204 /* test overlays application and removal in bad sequence */
205 overlay8 {
206 fragment@0 {
207 target-path = "/testcase-data/overlay-node/test-bus/test-unittest8";
208 __overlay__ {
209 status = "okay";
210 };
211 };
212 };
213 overlay9 {
214 fragment@0 {
215 target-path = "/testcase-data/overlay-node/test-bus/test-unittest8";
216 __overlay__ {
217 property-foo = "bar";
218 };
219 };
220 };
221
222 overlay10 {
223 fragment@0 {
224 target-path = "/testcase-data/overlay-node/test-bus";
225 __overlay__ {
226
227 /* suppress DTC warning */
228 #address-cells = <1>;
229 #size-cells = <0>;
230
231 test-unittest10 {
232 compatible = "unittest";
233 status = "okay";
234 reg = <10>;
235
236 #address-cells = <1>;
237 #size-cells = <0>;
238
239 test-unittest101 {
240 compatible = "unittest";
241 status = "okay";
242 reg = <1>;
243 };
244
245 };
246 };
247 };
248 };
249
250 overlay11 {
251 fragment@0 {
252 target-path = "/testcase-data/overlay-node/test-bus";
253 __overlay__ {
254
255 /* suppress DTC warning */
256 #address-cells = <1>;
257 #size-cells = <0>;
258
259 test-unittest11 {
260 compatible = "unittest";
261 status = "okay";
262 reg = <11>;
263
264 #address-cells = <1>;
265 #size-cells = <0>;
266
267 test-unittest111 {
268 compatible = "unittest";
269 status = "okay";
270 reg = <1>;
271 };
272
273 };
274 };
275 };
276 };
277
278 /* test enable using absolute target path (i2c) */
279 overlay12 {
280 fragment@0 {
281 target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12";
282 __overlay__ {
283 status = "okay";
284 };
285 };
286 };
287
288 /* test disable using absolute target path (i2c) */
289 overlay13 {
290 fragment@0 {
291 target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13";
292 __overlay__ {
293 status = "disabled";
294 };
295 };
296 };
297
298 /* test mux overlay */
299 overlay15 {
300 fragment@0 {
301 target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus";
302 __overlay__ {
303 #address-cells = <1>;
304 #size-cells = <0>;
305 test-unittest15 {
306 reg = <11>;
307 compatible = "unittest-i2c-mux";
308 status = "okay";
309
310 #address-cells = <1>;
311 #size-cells = <0>;
312
313 i2c@0 {
314 #address-cells = <1>;
315 #size-cells = <0>;
316 reg = <0>;
317
318 test-mux-dev {
319 reg = <32>;
320 compatible = "unittest-i2c-dev";
321 status = "okay";
322 };
323 };
324 };
325 };
326 };
327 };
328
329 }; 116 };
330}; 117};
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 7a9abaae874d..a23b54780c7d 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -45,6 +45,8 @@ static struct unittest_results {
45 failed; \ 45 failed; \
46}) 46})
47 47
48static int __init overlay_data_apply(const char *overlay_name, int *overlay_id);
49
48static void __init of_unittest_find_node_by_name(void) 50static void __init of_unittest_find_node_by_name(void)
49{ 51{
50 struct device_node *np; 52 struct device_node *np;
@@ -997,8 +999,7 @@ static int __init unittest_data_add(void)
997 } 999 }
998 1000
999 /* 1001 /*
1000 * This lock normally encloses of_overlay_apply() as well as 1002 * This lock normally encloses of_resolve_phandles()
1001 * of_resolve_phandles().
1002 */ 1003 */
1003 of_overlay_mutex_lock(); 1004 of_overlay_mutex_lock();
1004 1005
@@ -1191,12 +1192,12 @@ static int of_unittest_device_exists(int unittest_nr, enum overlay_type ovtype)
1191 return 0; 1192 return 0;
1192} 1193}
1193 1194
1194static const char *overlay_path(int nr) 1195static const char *overlay_name_from_nr(int nr)
1195{ 1196{
1196 static char buf[256]; 1197 static char buf[256];
1197 1198
1198 snprintf(buf, sizeof(buf) - 1, 1199 snprintf(buf, sizeof(buf) - 1,
1199 "/testcase-data/overlay%d", nr); 1200 "overlay_%d", nr);
1200 buf[sizeof(buf) - 1] = '\0'; 1201 buf[sizeof(buf) - 1] = '\0';
1201 1202
1202 return buf; 1203 return buf;
@@ -1263,25 +1264,19 @@ static void of_unittest_destroy_tracked_overlays(void)
1263 } while (defers > 0); 1264 } while (defers > 0);
1264} 1265}
1265 1266
1266static int of_unittest_apply_overlay(int overlay_nr, int unittest_nr, 1267static int __init of_unittest_apply_overlay(int overlay_nr, int unittest_nr,
1267 int *overlay_id) 1268 int *overlay_id)
1268{ 1269{
1269 struct device_node *np = NULL; 1270 struct device_node *np = NULL;
1271 const char *overlay_name;
1270 int ret; 1272 int ret;
1271 1273
1272 np = of_find_node_by_path(overlay_path(overlay_nr)); 1274 overlay_name = overlay_name_from_nr(overlay_nr);
1273 if (np == NULL) {
1274 unittest(0, "could not find overlay node @\"%s\"\n",
1275 overlay_path(overlay_nr));
1276 ret = -EINVAL;
1277 goto out;
1278 }
1279 1275
1280 *overlay_id = 0; 1276 ret = overlay_data_apply(overlay_name, overlay_id);
1281 ret = of_overlay_apply(np, overlay_id); 1277 if (!ret) {
1282 if (ret < 0) { 1278 unittest(0, "could not apply overlay \"%s\"\n",
1283 unittest(0, "could not create overlay from \"%s\"\n", 1279 overlay_name);
1284 overlay_path(overlay_nr));
1285 goto out; 1280 goto out;
1286 } 1281 }
1287 of_unittest_track_overlay(*overlay_id); 1282 of_unittest_track_overlay(*overlay_id);
@@ -1295,15 +1290,16 @@ out:
1295} 1290}
1296 1291
1297/* apply an overlay while checking before and after states */ 1292/* apply an overlay while checking before and after states */
1298static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr, 1293static int __init of_unittest_apply_overlay_check(int overlay_nr,
1299 int before, int after, enum overlay_type ovtype) 1294 int unittest_nr, int before, int after,
1295 enum overlay_type ovtype)
1300{ 1296{
1301 int ret, ovcs_id; 1297 int ret, ovcs_id;
1302 1298
1303 /* unittest device must not be in before state */ 1299 /* unittest device must not be in before state */
1304 if (of_unittest_device_exists(unittest_nr, ovtype) != before) { 1300 if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
1305 unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n", 1301 unittest(0, "%s with device @\"%s\" %s\n",
1306 overlay_path(overlay_nr), 1302 overlay_name_from_nr(overlay_nr),
1307 unittest_path(unittest_nr, ovtype), 1303 unittest_path(unittest_nr, ovtype),
1308 !before ? "enabled" : "disabled"); 1304 !before ? "enabled" : "disabled");
1309 return -EINVAL; 1305 return -EINVAL;
@@ -1318,8 +1314,8 @@ static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr,
1318 1314
1319 /* unittest device must be to set to after state */ 1315 /* unittest device must be to set to after state */
1320 if (of_unittest_device_exists(unittest_nr, ovtype) != after) { 1316 if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
1321 unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n", 1317 unittest(0, "%s failed to create @\"%s\" %s\n",
1322 overlay_path(overlay_nr), 1318 overlay_name_from_nr(overlay_nr),
1323 unittest_path(unittest_nr, ovtype), 1319 unittest_path(unittest_nr, ovtype),
1324 !after ? "enabled" : "disabled"); 1320 !after ? "enabled" : "disabled");
1325 return -EINVAL; 1321 return -EINVAL;
@@ -1329,7 +1325,7 @@ static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr,
1329} 1325}
1330 1326
1331/* apply an overlay and then revert it while checking before, after states */ 1327/* apply an overlay and then revert it while checking before, after states */
1332static int of_unittest_apply_revert_overlay_check(int overlay_nr, 1328static int __init of_unittest_apply_revert_overlay_check(int overlay_nr,
1333 int unittest_nr, int before, int after, 1329 int unittest_nr, int before, int after,
1334 enum overlay_type ovtype) 1330 enum overlay_type ovtype)
1335{ 1331{
@@ -1337,8 +1333,8 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
1337 1333
1338 /* unittest device must be in before state */ 1334 /* unittest device must be in before state */
1339 if (of_unittest_device_exists(unittest_nr, ovtype) != before) { 1335 if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
1340 unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n", 1336 unittest(0, "%s with device @\"%s\" %s\n",
1341 overlay_path(overlay_nr), 1337 overlay_name_from_nr(overlay_nr),
1342 unittest_path(unittest_nr, ovtype), 1338 unittest_path(unittest_nr, ovtype),
1343 !before ? "enabled" : "disabled"); 1339 !before ? "enabled" : "disabled");
1344 return -EINVAL; 1340 return -EINVAL;
@@ -1354,8 +1350,8 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
1354 1350
1355 /* unittest device must be in after state */ 1351 /* unittest device must be in after state */
1356 if (of_unittest_device_exists(unittest_nr, ovtype) != after) { 1352 if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
1357 unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n", 1353 unittest(0, "%s failed to create @\"%s\" %s\n",
1358 overlay_path(overlay_nr), 1354 overlay_name_from_nr(overlay_nr),
1359 unittest_path(unittest_nr, ovtype), 1355 unittest_path(unittest_nr, ovtype),
1360 !after ? "enabled" : "disabled"); 1356 !after ? "enabled" : "disabled");
1361 return -EINVAL; 1357 return -EINVAL;
@@ -1363,16 +1359,16 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
1363 1359
1364 ret = of_overlay_remove(&ovcs_id); 1360 ret = of_overlay_remove(&ovcs_id);
1365 if (ret != 0) { 1361 if (ret != 0) {
1366 unittest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n", 1362 unittest(0, "%s failed to be destroyed @\"%s\"\n",
1367 overlay_path(overlay_nr), 1363 overlay_name_from_nr(overlay_nr),
1368 unittest_path(unittest_nr, ovtype)); 1364 unittest_path(unittest_nr, ovtype));
1369 return ret; 1365 return ret;
1370 } 1366 }
1371 1367
1372 /* unittest device must be again in before state */ 1368 /* unittest device must be again in before state */
1373 if (of_unittest_device_exists(unittest_nr, PDEV_OVERLAY) != before) { 1369 if (of_unittest_device_exists(unittest_nr, PDEV_OVERLAY) != before) {
1374 unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n", 1370 unittest(0, "%s with device @\"%s\" %s\n",
1375 overlay_path(overlay_nr), 1371 overlay_name_from_nr(overlay_nr),
1376 unittest_path(unittest_nr, ovtype), 1372 unittest_path(unittest_nr, ovtype),
1377 !before ? "enabled" : "disabled"); 1373 !before ? "enabled" : "disabled");
1378 return -EINVAL; 1374 return -EINVAL;
@@ -1382,7 +1378,7 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
1382} 1378}
1383 1379
1384/* test activation of device */ 1380/* test activation of device */
1385static void of_unittest_overlay_0(void) 1381static void __init of_unittest_overlay_0(void)
1386{ 1382{
1387 int ret; 1383 int ret;
1388 1384
@@ -1395,7 +1391,7 @@ static void of_unittest_overlay_0(void)
1395} 1391}
1396 1392
1397/* test deactivation of device */ 1393/* test deactivation of device */
1398static void of_unittest_overlay_1(void) 1394static void __init of_unittest_overlay_1(void)
1399{ 1395{
1400 int ret; 1396 int ret;
1401 1397
@@ -1408,7 +1404,7 @@ static void of_unittest_overlay_1(void)
1408} 1404}
1409 1405
1410/* test activation of device */ 1406/* test activation of device */
1411static void of_unittest_overlay_2(void) 1407static void __init of_unittest_overlay_2(void)
1412{ 1408{
1413 int ret; 1409 int ret;
1414 1410
@@ -1421,7 +1417,7 @@ static void of_unittest_overlay_2(void)
1421} 1417}
1422 1418
1423/* test deactivation of device */ 1419/* test deactivation of device */
1424static void of_unittest_overlay_3(void) 1420static void __init of_unittest_overlay_3(void)
1425{ 1421{
1426 int ret; 1422 int ret;
1427 1423
@@ -1434,7 +1430,7 @@ static void of_unittest_overlay_3(void)
1434} 1430}
1435 1431
1436/* test activation of a full device node */ 1432/* test activation of a full device node */
1437static void of_unittest_overlay_4(void) 1433static void __init of_unittest_overlay_4(void)
1438{ 1434{
1439 int ret; 1435 int ret;
1440 1436
@@ -1447,7 +1443,7 @@ static void of_unittest_overlay_4(void)
1447} 1443}
1448 1444
1449/* test overlay apply/revert sequence */ 1445/* test overlay apply/revert sequence */
1450static void of_unittest_overlay_5(void) 1446static void __init of_unittest_overlay_5(void)
1451{ 1447{
1452 int ret; 1448 int ret;
1453 1449
@@ -1460,19 +1456,19 @@ static void of_unittest_overlay_5(void)
1460} 1456}
1461 1457
1462/* test overlay application in sequence */ 1458/* test overlay application in sequence */
1463static void of_unittest_overlay_6(void) 1459static void __init of_unittest_overlay_6(void)
1464{ 1460{
1465 struct device_node *np;
1466 int ret, i, ov_id[2], ovcs_id; 1461 int ret, i, ov_id[2], ovcs_id;
1467 int overlay_nr = 6, unittest_nr = 6; 1462 int overlay_nr = 6, unittest_nr = 6;
1468 int before = 0, after = 1; 1463 int before = 0, after = 1;
1464 const char *overlay_name;
1469 1465
1470 /* unittest device must be in before state */ 1466 /* unittest device must be in before state */
1471 for (i = 0; i < 2; i++) { 1467 for (i = 0; i < 2; i++) {
1472 if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY) 1468 if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
1473 != before) { 1469 != before) {
1474 unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n", 1470 unittest(0, "%s with device @\"%s\" %s\n",
1475 overlay_path(overlay_nr + i), 1471 overlay_name_from_nr(overlay_nr + i),
1476 unittest_path(unittest_nr + i, 1472 unittest_path(unittest_nr + i,
1477 PDEV_OVERLAY), 1473 PDEV_OVERLAY),
1478 !before ? "enabled" : "disabled"); 1474 !before ? "enabled" : "disabled");
@@ -1483,18 +1479,12 @@ static void of_unittest_overlay_6(void)
1483 /* apply the overlays */ 1479 /* apply the overlays */
1484 for (i = 0; i < 2; i++) { 1480 for (i = 0; i < 2; i++) {
1485 1481
1486 np = of_find_node_by_path(overlay_path(overlay_nr + i)); 1482 overlay_name = overlay_name_from_nr(overlay_nr + i);
1487 if (np == NULL) {
1488 unittest(0, "could not find overlay node @\"%s\"\n",
1489 overlay_path(overlay_nr + i));
1490 return;
1491 }
1492 1483
1493 ovcs_id = 0; 1484 ret = overlay_data_apply(overlay_name, &ovcs_id);
1494 ret = of_overlay_apply(np, &ovcs_id); 1485 if (!ret) {
1495 if (ret < 0) { 1486 unittest(0, "could not apply overlay \"%s\"\n",
1496 unittest(0, "could not create overlay from \"%s\"\n", 1487 overlay_name);
1497 overlay_path(overlay_nr + i));
1498 return; 1488 return;
1499 } 1489 }
1500 ov_id[i] = ovcs_id; 1490 ov_id[i] = ovcs_id;
@@ -1506,7 +1496,7 @@ static void of_unittest_overlay_6(void)
1506 if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY) 1496 if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
1507 != after) { 1497 != after) {
1508 unittest(0, "overlay @\"%s\" failed @\"%s\" %s\n", 1498 unittest(0, "overlay @\"%s\" failed @\"%s\" %s\n",
1509 overlay_path(overlay_nr + i), 1499 overlay_name_from_nr(overlay_nr + i),
1510 unittest_path(unittest_nr + i, 1500 unittest_path(unittest_nr + i,
1511 PDEV_OVERLAY), 1501 PDEV_OVERLAY),
1512 !after ? "enabled" : "disabled"); 1502 !after ? "enabled" : "disabled");
@@ -1518,8 +1508,8 @@ static void of_unittest_overlay_6(void)
1518 ovcs_id = ov_id[i]; 1508 ovcs_id = ov_id[i];
1519 ret = of_overlay_remove(&ovcs_id); 1509 ret = of_overlay_remove(&ovcs_id);
1520 if (ret != 0) { 1510 if (ret != 0) {
1521 unittest(0, "overlay @\"%s\" failed destroy @\"%s\"\n", 1511 unittest(0, "%s failed destroy @\"%s\"\n",
1522 overlay_path(overlay_nr + i), 1512 overlay_name_from_nr(overlay_nr + i),
1523 unittest_path(unittest_nr + i, 1513 unittest_path(unittest_nr + i,
1524 PDEV_OVERLAY)); 1514 PDEV_OVERLAY));
1525 return; 1515 return;
@@ -1531,8 +1521,8 @@ static void of_unittest_overlay_6(void)
1531 /* unittest device must be again in before state */ 1521 /* unittest device must be again in before state */
1532 if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY) 1522 if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
1533 != before) { 1523 != before) {
1534 unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n", 1524 unittest(0, "%s with device @\"%s\" %s\n",
1535 overlay_path(overlay_nr + i), 1525 overlay_name_from_nr(overlay_nr + i),
1536 unittest_path(unittest_nr + i, 1526 unittest_path(unittest_nr + i,
1537 PDEV_OVERLAY), 1527 PDEV_OVERLAY),
1538 !before ? "enabled" : "disabled"); 1528 !before ? "enabled" : "disabled");
@@ -1544,29 +1534,23 @@ static void of_unittest_overlay_6(void)
1544} 1534}
1545 1535
1546/* test overlay application in sequence */ 1536/* test overlay application in sequence */
1547static void of_unittest_overlay_8(void) 1537static void __init of_unittest_overlay_8(void)
1548{ 1538{
1549 struct device_node *np;
1550 int ret, i, ov_id[2], ovcs_id; 1539 int ret, i, ov_id[2], ovcs_id;
1551 int overlay_nr = 8, unittest_nr = 8; 1540 int overlay_nr = 8, unittest_nr = 8;
1541 const char *overlay_name;
1552 1542
1553 /* we don't care about device state in this test */ 1543 /* we don't care about device state in this test */
1554 1544
1555 /* apply the overlays */ 1545 /* apply the overlays */
1556 for (i = 0; i < 2; i++) { 1546 for (i = 0; i < 2; i++) {
1557 1547
1558 np = of_find_node_by_path(overlay_path(overlay_nr + i)); 1548 overlay_name = overlay_name_from_nr(overlay_nr + i);
1559 if (np == NULL) {
1560 unittest(0, "could not find overlay node @\"%s\"\n",
1561 overlay_path(overlay_nr + i));
1562 return;
1563 }
1564 1549
1565 ovcs_id = 0; 1550 ret = overlay_data_apply(overlay_name, &ovcs_id);
1566 ret = of_overlay_apply(np, &ovcs_id);
1567 if (ret < 0) { 1551 if (ret < 0) {
1568 unittest(0, "could not create overlay from \"%s\"\n", 1552 unittest(0, "could not apply overlay \"%s\"\n",
1569 overlay_path(overlay_nr + i)); 1553 overlay_name);
1570 return; 1554 return;
1571 } 1555 }
1572 ov_id[i] = ovcs_id; 1556 ov_id[i] = ovcs_id;
@@ -1577,8 +1561,8 @@ static void of_unittest_overlay_8(void)
1577 ovcs_id = ov_id[0]; 1561 ovcs_id = ov_id[0];
1578 ret = of_overlay_remove(&ovcs_id); 1562 ret = of_overlay_remove(&ovcs_id);
1579 if (ret == 0) { 1563 if (ret == 0) {
1580 unittest(0, "overlay @\"%s\" was destroyed @\"%s\"\n", 1564 unittest(0, "%s was destroyed @\"%s\"\n",
1581 overlay_path(overlay_nr + 0), 1565 overlay_name_from_nr(overlay_nr + 0),
1582 unittest_path(unittest_nr, 1566 unittest_path(unittest_nr,
1583 PDEV_OVERLAY)); 1567 PDEV_OVERLAY));
1584 return; 1568 return;
@@ -1589,8 +1573,8 @@ static void of_unittest_overlay_8(void)
1589 ovcs_id = ov_id[i]; 1573 ovcs_id = ov_id[i];
1590 ret = of_overlay_remove(&ovcs_id); 1574 ret = of_overlay_remove(&ovcs_id);
1591 if (ret != 0) { 1575 if (ret != 0) {
1592 unittest(0, "overlay @\"%s\" not destroyed @\"%s\"\n", 1576 unittest(0, "%s not destroyed @\"%s\"\n",
1593 overlay_path(overlay_nr + i), 1577 overlay_name_from_nr(overlay_nr + i),
1594 unittest_path(unittest_nr, 1578 unittest_path(unittest_nr,
1595 PDEV_OVERLAY)); 1579 PDEV_OVERLAY));
1596 return; 1580 return;
@@ -1602,7 +1586,7 @@ static void of_unittest_overlay_8(void)
1602} 1586}
1603 1587
1604/* test insertion of a bus with parent devices */ 1588/* test insertion of a bus with parent devices */
1605static void of_unittest_overlay_10(void) 1589static void __init of_unittest_overlay_10(void)
1606{ 1590{
1607 int ret; 1591 int ret;
1608 char *child_path; 1592 char *child_path;
@@ -1625,7 +1609,7 @@ static void of_unittest_overlay_10(void)
1625} 1609}
1626 1610
1627/* test insertion of a bus with parent devices (and revert) */ 1611/* test insertion of a bus with parent devices (and revert) */
1628static void of_unittest_overlay_11(void) 1612static void __init of_unittest_overlay_11(void)
1629{ 1613{
1630 int ret; 1614 int ret;
1631 1615
@@ -1891,7 +1875,7 @@ static void of_unittest_overlay_i2c_cleanup(void)
1891 i2c_del_driver(&unittest_i2c_dev_driver); 1875 i2c_del_driver(&unittest_i2c_dev_driver);
1892} 1876}
1893 1877
1894static void of_unittest_overlay_i2c_12(void) 1878static void __init of_unittest_overlay_i2c_12(void)
1895{ 1879{
1896 int ret; 1880 int ret;
1897 1881
@@ -1904,7 +1888,7 @@ static void of_unittest_overlay_i2c_12(void)
1904} 1888}
1905 1889
1906/* test deactivation of device */ 1890/* test deactivation of device */
1907static void of_unittest_overlay_i2c_13(void) 1891static void __init of_unittest_overlay_i2c_13(void)
1908{ 1892{
1909 int ret; 1893 int ret;
1910 1894
@@ -1921,7 +1905,7 @@ static void of_unittest_overlay_i2c_14(void)
1921{ 1905{
1922} 1906}
1923 1907
1924static void of_unittest_overlay_i2c_15(void) 1908static void __init of_unittest_overlay_i2c_15(void)
1925{ 1909{
1926 int ret; 1910 int ret;
1927 1911
@@ -2023,23 +2007,38 @@ static inline void __init of_unittest_overlay(void) { }
2023 extern uint8_t __dtb_##name##_begin[]; \ 2007 extern uint8_t __dtb_##name##_begin[]; \
2024 extern uint8_t __dtb_##name##_end[] 2008 extern uint8_t __dtb_##name##_end[]
2025 2009
2026#define OVERLAY_INFO(name, expected) \ 2010#define OVERLAY_INFO(overlay_name, expected) \
2027{ .dtb_begin = __dtb_##name##_begin, \ 2011{ .dtb_begin = __dtb_##overlay_name##_begin, \
2028 .dtb_end = __dtb_##name##_end, \ 2012 .dtb_end = __dtb_##overlay_name##_end, \
2029 .expected_result = expected, \ 2013 .expected_result = expected, \
2014 .name = #overlay_name, \
2030} 2015}
2031 2016
2032struct overlay_info { 2017struct overlay_info {
2033 uint8_t *dtb_begin; 2018 uint8_t *dtb_begin;
2034 uint8_t *dtb_end; 2019 uint8_t *dtb_end;
2035 void *data; 2020 int expected_result;
2036 struct device_node *np_overlay; 2021 int overlay_id;
2037 int expected_result; 2022 char *name;
2038 int overlay_id;
2039}; 2023};
2040 2024
2041OVERLAY_INFO_EXTERN(overlay_base); 2025OVERLAY_INFO_EXTERN(overlay_base);
2042OVERLAY_INFO_EXTERN(overlay); 2026OVERLAY_INFO_EXTERN(overlay);
2027OVERLAY_INFO_EXTERN(overlay_0);
2028OVERLAY_INFO_EXTERN(overlay_1);
2029OVERLAY_INFO_EXTERN(overlay_2);
2030OVERLAY_INFO_EXTERN(overlay_3);
2031OVERLAY_INFO_EXTERN(overlay_4);
2032OVERLAY_INFO_EXTERN(overlay_5);
2033OVERLAY_INFO_EXTERN(overlay_6);
2034OVERLAY_INFO_EXTERN(overlay_7);
2035OVERLAY_INFO_EXTERN(overlay_8);
2036OVERLAY_INFO_EXTERN(overlay_9);
2037OVERLAY_INFO_EXTERN(overlay_10);
2038OVERLAY_INFO_EXTERN(overlay_11);
2039OVERLAY_INFO_EXTERN(overlay_12);
2040OVERLAY_INFO_EXTERN(overlay_13);
2041OVERLAY_INFO_EXTERN(overlay_15);
2043OVERLAY_INFO_EXTERN(overlay_bad_phandle); 2042OVERLAY_INFO_EXTERN(overlay_bad_phandle);
2044OVERLAY_INFO_EXTERN(overlay_bad_symbol); 2043OVERLAY_INFO_EXTERN(overlay_bad_symbol);
2045 2044
@@ -2047,6 +2046,21 @@ OVERLAY_INFO_EXTERN(overlay_bad_symbol);
2047static struct overlay_info overlays[] = { 2046static struct overlay_info overlays[] = {
2048 OVERLAY_INFO(overlay_base, -9999), 2047 OVERLAY_INFO(overlay_base, -9999),
2049 OVERLAY_INFO(overlay, 0), 2048 OVERLAY_INFO(overlay, 0),
2049 OVERLAY_INFO(overlay_0, 0),
2050 OVERLAY_INFO(overlay_1, 0),
2051 OVERLAY_INFO(overlay_2, 0),
2052 OVERLAY_INFO(overlay_3, 0),
2053 OVERLAY_INFO(overlay_4, 0),
2054 OVERLAY_INFO(overlay_5, 0),
2055 OVERLAY_INFO(overlay_6, 0),
2056 OVERLAY_INFO(overlay_7, 0),
2057 OVERLAY_INFO(overlay_8, 0),
2058 OVERLAY_INFO(overlay_9, 0),
2059 OVERLAY_INFO(overlay_10, 0),
2060 OVERLAY_INFO(overlay_11, 0),
2061 OVERLAY_INFO(overlay_12, 0),
2062 OVERLAY_INFO(overlay_13, 0),
2063 OVERLAY_INFO(overlay_15, 0),
2050 OVERLAY_INFO(overlay_bad_phandle, -EINVAL), 2064 OVERLAY_INFO(overlay_bad_phandle, -EINVAL),
2051 OVERLAY_INFO(overlay_bad_symbol, -EINVAL), 2065 OVERLAY_INFO(overlay_bad_symbol, -EINVAL),
2052 {} 2066 {}
@@ -2077,6 +2091,7 @@ void __init unittest_unflatten_overlay_base(void)
2077{ 2091{
2078 struct overlay_info *info; 2092 struct overlay_info *info;
2079 u32 data_size; 2093 u32 data_size;
2094 void *new_fdt;
2080 u32 size; 2095 u32 size;
2081 2096
2082 info = &overlays[0]; 2097 info = &overlays[0];
@@ -2098,17 +2113,16 @@ void __init unittest_unflatten_overlay_base(void)
2098 return; 2113 return;
2099 } 2114 }
2100 2115
2101 info->data = dt_alloc_memory(size, roundup_pow_of_two(FDT_V17_SIZE)); 2116 new_fdt = dt_alloc_memory(size, roundup_pow_of_two(FDT_V17_SIZE));
2102 if (!info->data) { 2117 if (!new_fdt) {
2103 pr_err("alloc for dtb 'overlay_base' failed"); 2118 pr_err("alloc for dtb 'overlay_base' failed");
2104 return; 2119 return;
2105 } 2120 }
2106 2121
2107 memcpy(info->data, info->dtb_begin, size); 2122 memcpy(new_fdt, info->dtb_begin, size);
2108 2123
2109 __unflatten_device_tree(info->data, NULL, &info->np_overlay, 2124 __unflatten_device_tree(new_fdt, NULL, &overlay_base_root,
2110 dt_alloc_memory, true); 2125 dt_alloc_memory, true);
2111 overlay_base_root = info->np_overlay;
2112} 2126}
2113 2127
2114/* 2128/*
@@ -2122,73 +2136,44 @@ void __init unittest_unflatten_overlay_base(void)
2122 * 2136 *
2123 * Return 0 on unexpected error. 2137 * Return 0 on unexpected error.
2124 */ 2138 */
2125static int __init overlay_data_add(int onum) 2139static int __init overlay_data_apply(const char *overlay_name, int *overlay_id)
2126{ 2140{
2127 struct overlay_info *info; 2141 struct overlay_info *info;
2142 int found = 0;
2128 int k; 2143 int k;
2129 int ret; 2144 int ret;
2130 u32 size; 2145 u32 size;
2131 u32 size_from_header;
2132 2146
2133 for (k = 0, info = overlays; info; info++, k++) { 2147 for (k = 0, info = overlays; info && info->name; info++, k++) {
2134 if (k == onum) 2148 if (!strcmp(overlay_name, info->name)) {
2149 found = 1;
2135 break; 2150 break;
2151 }
2136 } 2152 }
2137 if (onum > k) 2153 if (!found) {
2154 pr_err("no overlay data for %s\n", overlay_name);
2138 return 0; 2155 return 0;
2156 }
2139 2157
2140 size = info->dtb_end - info->dtb_begin; 2158 size = info->dtb_end - info->dtb_begin;
2141 if (!size) { 2159 if (!size) {
2142 pr_err("no overlay to attach, %d\n", onum); 2160 pr_err("no overlay data for %s\n", overlay_name);
2143 ret = 0; 2161 ret = 0;
2144 } 2162 }
2145 2163
2146 size_from_header = fdt_totalsize(info->dtb_begin); 2164 ret = of_overlay_fdt_apply(info->dtb_begin, size, &info->overlay_id);
2147 if (size_from_header != size) { 2165 if (overlay_id)
2148 pr_err("overlay header totalsize != actual size, %d", onum); 2166 *overlay_id = info->overlay_id;
2149 return 0; 2167 if (ret < 0)
2150 } 2168 goto out;
2151
2152 /*
2153 * Must create permanent copy of FDT because of_fdt_unflatten_tree()
2154 * will create pointers to the passed in FDT in the EDT.
2155 */
2156 info->data = kmemdup(info->dtb_begin, size, GFP_KERNEL);
2157 if (!info->data) {
2158 pr_err("unable to allocate memory for data, %d\n", onum);
2159 return 0;
2160 }
2161
2162 of_fdt_unflatten_tree(info->data, NULL, &info->np_overlay);
2163 if (!info->np_overlay) {
2164 pr_err("unable to unflatten overlay, %d\n", onum);
2165 ret = 0;
2166 goto out_free_data;
2167 }
2168
2169 info->overlay_id = 0;
2170 ret = of_overlay_apply(info->np_overlay, &info->overlay_id);
2171 if (ret < 0) {
2172 pr_err("of_overlay_apply() (ret=%d), %d\n", ret, onum);
2173 goto out_free_np_overlay;
2174 }
2175
2176 pr_debug("__dtb_overlay_begin applied, overlay id %d\n", ret);
2177
2178 goto out;
2179
2180out_free_np_overlay:
2181 /*
2182 * info->np_overlay is the unflattened device tree
2183 * It has not been spliced into the live tree.
2184 */
2185
2186 /* todo: function to free unflattened device tree */
2187 2169
2188out_free_data: 2170 pr_debug("%s applied\n", overlay_name);
2189 kfree(info->data);
2190 2171
2191out: 2172out:
2173 if (ret != info->expected_result)
2174 pr_err("of_overlay_fdt_apply() expected %d, ret=%d, %s\n",
2175 info->expected_result, ret, overlay_name);
2176
2192 return (ret == info->expected_result); 2177 return (ret == info->expected_result);
2193} 2178}
2194 2179
@@ -2290,18 +2275,29 @@ static __init void of_unittest_overlay_high_level(void)
2290 __of_attach_node_sysfs(np); 2275 __of_attach_node_sysfs(np);
2291 2276
2292 if (of_symbols) { 2277 if (of_symbols) {
2278 struct property *new_prop;
2293 for_each_property_of_node(overlay_base_symbols, prop) { 2279 for_each_property_of_node(overlay_base_symbols, prop) {
2294 ret = __of_add_property(of_symbols, prop); 2280
2281 new_prop = __of_prop_dup(prop, GFP_KERNEL);
2282 if (!new_prop) {
2283 unittest(0, "__of_prop_dup() of '%s' from overlay_base node __symbols__",
2284 prop->name);
2285 goto err_unlock;
2286 }
2287 ret = __of_add_property(of_symbols, new_prop);
2295 if (ret) { 2288 if (ret) {
2296 unittest(0, 2289 if (!strcmp(new_prop->name, "name")) {
2297 "duplicate property '%s' in overlay_base node __symbols__", 2290 /* auto-generated by unflatten */
2291 ret = 0;
2292 continue;
2293 }
2294 unittest(0, "duplicate property '%s' in overlay_base node __symbols__",
2298 prop->name); 2295 prop->name);
2299 goto err_unlock; 2296 goto err_unlock;
2300 } 2297 }
2301 ret = __of_add_property_sysfs(of_symbols, prop); 2298 ret = __of_add_property_sysfs(of_symbols, new_prop);
2302 if (ret) { 2299 if (ret) {
2303 unittest(0, 2300 unittest(0, "unable to add property '%s' in overlay_base node __symbols__ to sysfs",
2304 "unable to add property '%s' in overlay_base node __symbols__ to sysfs",
2305 prop->name); 2301 prop->name);
2306 goto err_unlock; 2302 goto err_unlock;
2307 } 2303 }
@@ -2313,13 +2309,13 @@ static __init void of_unittest_overlay_high_level(void)
2313 2309
2314 /* now do the normal overlay usage test */ 2310 /* now do the normal overlay usage test */
2315 2311
2316 unittest(overlay_data_add(1), 2312 unittest(overlay_data_apply("overlay", NULL),
2317 "Adding overlay 'overlay' failed\n"); 2313 "Adding overlay 'overlay' failed\n");
2318 2314
2319 unittest(overlay_data_add(2), 2315 unittest(overlay_data_apply("overlay_bad_phandle", NULL),
2320 "Adding overlay 'overlay_bad_phandle' failed\n"); 2316 "Adding overlay 'overlay_bad_phandle' failed\n");
2321 2317
2322 unittest(overlay_data_add(3), 2318 unittest(overlay_data_apply("overlay_bad_symbol", NULL),
2323 "Adding overlay 'overlay_bad_symbol' failed\n"); 2319 "Adding overlay 'overlay_bad_symbol' failed\n");
2324 2320
2325 return; 2321 return;
diff --git a/include/linux/of.h b/include/linux/of.h
index da1ee95241c1..ebf22dd0860c 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1359,8 +1359,8 @@ struct of_overlay_notify_data {
1359 1359
1360#ifdef CONFIG_OF_OVERLAY 1360#ifdef CONFIG_OF_OVERLAY
1361 1361
1362/* ID based overlays; the API for external users */ 1362int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
1363int of_overlay_apply(struct device_node *tree, int *ovcs_id); 1363 int *ovcs_id);
1364int of_overlay_remove(int *ovcs_id); 1364int of_overlay_remove(int *ovcs_id);
1365int of_overlay_remove_all(void); 1365int of_overlay_remove_all(void);
1366 1366
@@ -1369,7 +1369,7 @@ int of_overlay_notifier_unregister(struct notifier_block *nb);
1369 1369
1370#else 1370#else
1371 1371
1372static inline int of_overlay_apply(struct device_node *tree, int *ovcs_id) 1372static inline int of_overlay_fdt_apply(void *overlay_fdt, int *ovcs_id)
1373{ 1373{
1374 return -ENOTSUPP; 1374 return -ENOTSUPP;
1375} 1375}