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(). -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJam68pAAoJEKFvmrgMstOVJEkQAIkYv+041F1RE8pezo8FvO7k GJnyiVVhiWEdddOfNofaR05im7QnrVLamKjmVgCZL/5ScF3pB0bkfxgbPn8oyjQ5 PCDriQOZ+6DFjCWNtib8K2ZW150QMMI5V4YLSooIKRoH/Opm4VEP1k94sKWmrELt ja2WwI9+Wc6oiQe8n7okBgg6pKJ9dakeYlWdCAvDXPcgEdwrqgsQVj+gYRAqDuN7 MKQLF9uKNP5XrIksKFBprIDadXHVa7AmxYN9nTWQvK2b1NGssNcr3jxG0JSwxPUN z+ov828nU/M68o1n6d6ADwRN2XFLWWFd1pZyMUErPWREIE8mqlvwux+Z8SpjLPd3 T4fMs8vtURf/GlH3ENiulKOs3/KHmvEDBcmAQc7jI/JQQeCvvom20iLd042oUaKP 3HKstI6nIPkKhEJ7MaCSzRjHN2HfXFAEcZGwSxYCsozOrWsf+lSkk4coK7777lJL 6avpU6CX4t/Kd2jIM1zddFS+hnWtnmS8eiUHqsj1ps6p8NzkAehwq6JRQ/oZo3sJ lQvtmip53VQYO1DbsnbGHeYjfsqfnaTY635asB27gzux1baqxy0liY6I4TvqsEr6 VW9HUvbtlFFzRqP08tkpOPOPeaH7fsygiBzKtk9Ezpoz/A5KhtAXifFbAe4yHkaF 4Hm3vYwJ7xJ7OpjxGrD0 =f/Se -----END PGP SIGNATURE----- Merge tag 'overlay_apply_fdt_v7-for-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/frowand/linux into dt/next DT overlay applying rework from Frank Rowand: "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()."
This commit is contained in:
commit
b46c78661c
|
@ -87,8 +87,8 @@ Overlay in-kernel API
|
|||
|
||||
The API is quite easy to use.
|
||||
|
||||
1. Call of_overlay_apply() to create and apply an overlay changeset. The return
|
||||
value is an error or a cookie identifying this overlay.
|
||||
1. Call of_overlay_fdt_apply() to create and apply an overlay changeset. The
|
||||
return value is an error or a cookie identifying this overlay.
|
||||
|
||||
2. Call of_overlay_remove() to remove and cleanup the overlay changeset
|
||||
previously created via the call to of_overlay_apply(). Removal of an overlay
|
||||
|
|
|
@ -259,7 +259,7 @@ static void __init dtb_apic_setup(void)
|
|||
dtb_ioapic_setup();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF_FLATTREE
|
||||
#ifdef CONFIG_OF_EARLY_FLATTREE
|
||||
static void __init x86_flattree_get_config(void)
|
||||
{
|
||||
u32 size, map_len;
|
||||
|
|
|
@ -92,6 +92,7 @@ config OF_RESOLVE
|
|||
config OF_OVERLAY
|
||||
bool "Device Tree overlays"
|
||||
select OF_DYNAMIC
|
||||
select OF_FLATTREE
|
||||
select OF_RESOLVE
|
||||
help
|
||||
Overlays are a method to dynamically modify part of the kernel's
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/idr.h>
|
||||
|
||||
|
@ -33,7 +35,9 @@ struct fragment {
|
|||
|
||||
/**
|
||||
* struct overlay_changeset
|
||||
* @id: changeset identifier
|
||||
* @ovcs_list: list on which we are located
|
||||
* @fdt: FDT that was unflattened to create @overlay_tree
|
||||
* @overlay_tree: expanded device tree that contains the fragment nodes
|
||||
* @count: count of fragment structures
|
||||
* @fragments: fragment nodes in the overlay expanded device tree
|
||||
|
@ -43,6 +47,7 @@ struct fragment {
|
|||
struct overlay_changeset {
|
||||
int id;
|
||||
struct list_head ovcs_list;
|
||||
const void *fdt;
|
||||
struct device_node *overlay_tree;
|
||||
int count;
|
||||
struct fragment *fragments;
|
||||
|
@ -483,27 +488,38 @@ static int build_changeset(struct overlay_changeset *ovcs)
|
|||
*/
|
||||
static struct device_node *find_target_node(struct device_node *info_node)
|
||||
{
|
||||
struct device_node *node;
|
||||
const char *path;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(info_node, "target", &val);
|
||||
if (!ret)
|
||||
return of_find_node_by_phandle(val);
|
||||
if (!ret) {
|
||||
node = of_find_node_by_phandle(val);
|
||||
if (!node)
|
||||
pr_err("find target, node: %pOF, phandle 0x%x not found\n",
|
||||
info_node, val);
|
||||
return node;
|
||||
}
|
||||
|
||||
ret = of_property_read_string(info_node, "target-path", &path);
|
||||
if (!ret)
|
||||
return of_find_node_by_path(path);
|
||||
if (!ret) {
|
||||
node = of_find_node_by_path(path);
|
||||
if (!node)
|
||||
pr_err("find target, node: %pOF, path '%s' not found\n",
|
||||
info_node, path);
|
||||
return node;
|
||||
}
|
||||
|
||||
pr_err("Failed to find target for node %p (%s)\n",
|
||||
info_node, info_node->name);
|
||||
pr_err("find target, node: %pOF, no target property\n", info_node);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* init_overlay_changeset() - initialize overlay changeset from overlay tree
|
||||
* @ovcs Overlay changeset to build
|
||||
* @ovcs: Overlay changeset to build
|
||||
* @fdt: the FDT that was unflattened to create @tree
|
||||
* @tree: Contains all the overlay fragments and overlay fixup nodes
|
||||
*
|
||||
* Initialize @ovcs. Populate @ovcs->fragments with node information from
|
||||
|
@ -514,7 +530,7 @@ static struct device_node *find_target_node(struct device_node *info_node)
|
|||
* detected in @tree, or -ENOSPC if idr_alloc() error.
|
||||
*/
|
||||
static int init_overlay_changeset(struct overlay_changeset *ovcs,
|
||||
struct device_node *tree)
|
||||
const void *fdt, struct device_node *tree)
|
||||
{
|
||||
struct device_node *node, *overlay_node;
|
||||
struct fragment *fragment;
|
||||
|
@ -535,6 +551,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
|
|||
pr_debug("%s() tree is not root\n", __func__);
|
||||
|
||||
ovcs->overlay_tree = tree;
|
||||
ovcs->fdt = fdt;
|
||||
|
||||
INIT_LIST_HEAD(&ovcs->ovcs_list);
|
||||
|
||||
|
@ -606,6 +623,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
|
|||
}
|
||||
|
||||
if (!cnt) {
|
||||
pr_err("no fragments or symbols in overlay\n");
|
||||
ret = -EINVAL;
|
||||
goto err_free_fragments;
|
||||
}
|
||||
|
@ -642,11 +660,24 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs)
|
|||
}
|
||||
kfree(ovcs->fragments);
|
||||
|
||||
/*
|
||||
* TODO
|
||||
*
|
||||
* would like to: kfree(ovcs->overlay_tree);
|
||||
* but can not since drivers may have pointers into this data
|
||||
*
|
||||
* would like to: kfree(ovcs->fdt);
|
||||
* but can not since drivers may have pointers into this data
|
||||
*/
|
||||
|
||||
kfree(ovcs);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* internal documentation
|
||||
*
|
||||
* of_overlay_apply() - Create and apply an overlay changeset
|
||||
* @fdt: the FDT that was unflattened to create @tree
|
||||
* @tree: Expanded overlay device tree
|
||||
* @ovcs_id: Pointer to overlay changeset id
|
||||
*
|
||||
|
@ -685,21 +716,29 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs)
|
|||
* id is returned to *ovcs_id.
|
||||
*/
|
||||
|
||||
int of_overlay_apply(struct device_node *tree, int *ovcs_id)
|
||||
static int of_overlay_apply(const void *fdt, struct device_node *tree,
|
||||
int *ovcs_id)
|
||||
{
|
||||
struct overlay_changeset *ovcs;
|
||||
int ret = 0, ret_revert, ret_tmp;
|
||||
|
||||
*ovcs_id = 0;
|
||||
/*
|
||||
* As of this point, fdt and tree belong to the overlay changeset.
|
||||
* overlay changeset code is responsible for freeing them.
|
||||
*/
|
||||
|
||||
if (devicetree_corrupt()) {
|
||||
pr_err("devicetree state suspect, refuse to apply overlay\n");
|
||||
kfree(fdt);
|
||||
kfree(tree);
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL);
|
||||
if (!ovcs) {
|
||||
kfree(fdt);
|
||||
kfree(tree);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -709,12 +748,17 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id)
|
|||
|
||||
ret = of_resolve_phandles(tree);
|
||||
if (ret)
|
||||
goto err_free_overlay_changeset;
|
||||
goto err_free_tree;
|
||||
|
||||
ret = init_overlay_changeset(ovcs, tree);
|
||||
ret = init_overlay_changeset(ovcs, fdt, tree);
|
||||
if (ret)
|
||||
goto err_free_overlay_changeset;
|
||||
goto err_free_tree;
|
||||
|
||||
/*
|
||||
* after overlay_notify(), ovcs->overlay_tree related pointers may have
|
||||
* leaked to drivers, so can not kfree() tree, aka ovcs->overlay_tree;
|
||||
* and can not free fdt, aka ovcs->fdt
|
||||
*/
|
||||
ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY);
|
||||
if (ret) {
|
||||
pr_err("overlay changeset pre-apply notify error %d\n", ret);
|
||||
|
@ -754,6 +798,10 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id)
|
|||
|
||||
goto out_unlock;
|
||||
|
||||
err_free_tree:
|
||||
kfree(fdt);
|
||||
kfree(tree);
|
||||
|
||||
err_free_overlay_changeset:
|
||||
free_overlay_changeset(ovcs);
|
||||
|
||||
|
@ -766,7 +814,63 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id)
|
|||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_overlay_apply);
|
||||
|
||||
int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
|
||||
int *ovcs_id)
|
||||
{
|
||||
const void *new_fdt;
|
||||
int ret;
|
||||
u32 size;
|
||||
struct device_node *overlay_root;
|
||||
|
||||
*ovcs_id = 0;
|
||||
ret = 0;
|
||||
|
||||
if (overlay_fdt_size < sizeof(struct fdt_header) ||
|
||||
fdt_check_header(overlay_fdt)) {
|
||||
pr_err("Invalid overlay_fdt header\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size = fdt_totalsize(overlay_fdt);
|
||||
if (overlay_fdt_size < size)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Must create permanent copy of FDT because of_fdt_unflatten_tree()
|
||||
* will create pointers to the passed in FDT in the unflattened tree.
|
||||
*/
|
||||
new_fdt = kmemdup(overlay_fdt, size, GFP_KERNEL);
|
||||
if (!new_fdt)
|
||||
return -ENOMEM;
|
||||
|
||||
of_fdt_unflatten_tree(new_fdt, NULL, &overlay_root);
|
||||
if (!overlay_root) {
|
||||
pr_err("unable to unflatten overlay_fdt\n");
|
||||
ret = -EINVAL;
|
||||
goto out_free_new_fdt;
|
||||
}
|
||||
|
||||
ret = of_overlay_apply(new_fdt, overlay_root, ovcs_id);
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* new_fdt and overlay_root now belong to the overlay
|
||||
* changeset.
|
||||
* overlay changeset code is responsible for freeing them.
|
||||
*/
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
out_free_new_fdt:
|
||||
kfree(new_fdt);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_overlay_fdt_apply);
|
||||
|
||||
/*
|
||||
* Find @np in @tree.
|
||||
|
|
|
@ -269,17 +269,11 @@ int of_resolve_phandles(struct device_node *overlay)
|
|||
goto out;
|
||||
}
|
||||
|
||||
#if 0
|
||||
Temporarily disable check so that old style overlay unittests
|
||||
do not fail when of_resolve_phandles() is moved into
|
||||
of_overlay_apply().
|
||||
|
||||
if (!of_node_check_flag(overlay, OF_DETACHED)) {
|
||||
pr_err("overlay not detached\n");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
phandle_delta = live_tree_max_phandle() + 1;
|
||||
adjust_overlay_phandles(overlay, phandle_delta);
|
||||
|
|
|
@ -1,8 +1,22 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
DTC_FLAGS_testcases := -Wno-interrupts_property
|
||||
obj-y += testcases.dtb.o
|
||||
|
||||
obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \
|
||||
overlay_0.dtb.o \
|
||||
overlay_1.dtb.o \
|
||||
overlay_2.dtb.o \
|
||||
overlay_3.dtb.o \
|
||||
overlay_4.dtb.o \
|
||||
overlay_5.dtb.o \
|
||||
overlay_6.dtb.o \
|
||||
overlay_7.dtb.o \
|
||||
overlay_8.dtb.o \
|
||||
overlay_9.dtb.o \
|
||||
overlay_10.dtb.o \
|
||||
overlay_11.dtb.o \
|
||||
overlay_12.dtb.o \
|
||||
overlay_13.dtb.o \
|
||||
overlay_15.dtb.o \
|
||||
overlay_bad_phandle.dtb.o \
|
||||
overlay_bad_symbol.dtb.o \
|
||||
overlay_base.dtb.o
|
||||
|
@ -10,10 +24,14 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \
|
|||
targets += $(foreach suffix, dtb dtb.S, $(patsubst %.dtb.o,%.$(suffix),$(obj-y)))
|
||||
|
||||
# enable creation of __symbols__ node
|
||||
DTC_FLAGS_overlay := -@
|
||||
DTC_FLAGS_overlay_bad_phandle := -@
|
||||
DTC_FLAGS_overlay_bad_symbol := -@
|
||||
DTC_FLAGS_overlay_base := -@
|
||||
DTC_FLAGS_overlay += -@
|
||||
DTC_FLAGS_overlay_bad_phandle += -@
|
||||
DTC_FLAGS_overlay_bad_symbol += -@
|
||||
DTC_FLAGS_overlay_base += -@
|
||||
DTC_FLAGS_testcases += -@
|
||||
|
||||
# suppress warnings about intentional errors
|
||||
DTC_FLAGS_testcases += -Wno-interrupts_property
|
||||
|
||||
.PRECIOUS: \
|
||||
$(obj)/%.dtb.S \
|
||||
|
|
|
@ -2,76 +2,63 @@
|
|||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/ {
|
||||
&electric_1 {
|
||||
|
||||
fragment@0 {
|
||||
target = <&electric_1>;
|
||||
status = "okay";
|
||||
|
||||
__overlay__ {
|
||||
status = "okay";
|
||||
|
||||
hvac_2: hvac-large-1 {
|
||||
compatible = "ot,hvac-large";
|
||||
heat-range = < 40 75 >;
|
||||
cool-range = < 65 80 >;
|
||||
};
|
||||
};
|
||||
hvac_2: hvac-large-1 {
|
||||
compatible = "ot,hvac-large";
|
||||
heat-range = < 40 75 >;
|
||||
cool-range = < 65 80 >;
|
||||
};
|
||||
|
||||
fragment@1 {
|
||||
target = <&rides_1>;
|
||||
|
||||
__overlay__ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
status = "okay";
|
||||
|
||||
ride@100 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
track@30 {
|
||||
incline-up = < 48 32 16 >;
|
||||
};
|
||||
|
||||
track@40 {
|
||||
incline-up = < 47 31 15 >;
|
||||
};
|
||||
};
|
||||
|
||||
ride_200: ride@200 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "ot,ferris-wheel";
|
||||
reg = < 0x00000200 0x100 >;
|
||||
hvac-provider = < &hvac_2 >;
|
||||
hvac-thermostat = < 27 32 > ;
|
||||
hvac-zones = < 12 5 >;
|
||||
hvac-zone-names = "operator", "snack-bar";
|
||||
spin-controller = < &spin_ctrl_1 3 >;
|
||||
spin-rph = < 30 >;
|
||||
gondolas = < 16 >;
|
||||
gondola-capacity = < 6 >;
|
||||
|
||||
ride_200_left: track@10 {
|
||||
reg = < 0x00000010 0x10 >;
|
||||
};
|
||||
|
||||
ride_200_right: track@20 {
|
||||
reg = < 0x00000020 0x10 >;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fragment@2 {
|
||||
target = <&lights_2>;
|
||||
|
||||
__overlay__ {
|
||||
status = "okay";
|
||||
color = "purple", "white", "red", "green";
|
||||
rate = < 3 256 >;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
&rides_1 {
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
status = "okay";
|
||||
|
||||
ride@100 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
track@30 {
|
||||
incline-up = < 48 32 16 >;
|
||||
};
|
||||
|
||||
track@40 {
|
||||
incline-up = < 47 31 15 >;
|
||||
};
|
||||
};
|
||||
|
||||
ride_200: ride@200 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "ot,ferris-wheel";
|
||||
reg = < 0x00000200 0x100 >;
|
||||
hvac-provider = < &hvac_2 >;
|
||||
hvac-thermostat = < 27 32 > ;
|
||||
hvac-zones = < 12 5 >;
|
||||
hvac-zone-names = "operator", "snack-bar";
|
||||
spin-controller = < &spin_ctrl_1 3 >;
|
||||
spin-rph = < 30 >;
|
||||
gondolas = < 16 >;
|
||||
gondola-capacity = < 6 >;
|
||||
|
||||
ride_200_left: track@10 {
|
||||
reg = < 0x00000010 0x10 >;
|
||||
};
|
||||
|
||||
ride_200_right: track@20 {
|
||||
reg = < 0x00000020 0x10 >;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&lights_2 {
|
||||
|
||||
status = "okay";
|
||||
color = "purple", "white", "red", "green";
|
||||
rate = < 3 256 >;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/ {
|
||||
/* overlay_0 - enable using absolute target path */
|
||||
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/test-unittest0";
|
||||
__overlay__ {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/ {
|
||||
/* overlay_1 - disable using absolute target path */
|
||||
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/test-unittest1";
|
||||
__overlay__ {
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/* overlay_10 */
|
||||
/* overlays 8, 9, 10, 11 application and removal in bad sequence */
|
||||
|
||||
&unittest_test_bus {
|
||||
/* suppress DTC warning */
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
test-unittest10 {
|
||||
compatible = "unittest";
|
||||
status = "okay";
|
||||
reg = <10>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
test-unittest101 {
|
||||
compatible = "unittest";
|
||||
status = "okay";
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/* overlay_11 */
|
||||
/* overlays 8, 9, 10, 11 application and removal in bad sequence */
|
||||
|
||||
&unittest_test_bus {
|
||||
/* suppress DTC warning */
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
test-unittest11 {
|
||||
compatible = "unittest";
|
||||
status = "okay";
|
||||
reg = <11>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
test-unittest111 {
|
||||
compatible = "unittest";
|
||||
status = "okay";
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/ {
|
||||
/* overlay_12 - enable using absolute target path (i2c) */
|
||||
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12";
|
||||
__overlay__ {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/ {
|
||||
/* overlay_13 - disable using absolute target path (i2c) */
|
||||
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13";
|
||||
__overlay__ {
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/* overlay_15 - mux overlay */
|
||||
|
||||
&unittest_i2c_test_bus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
test-unittest15 {
|
||||
reg = <11>;
|
||||
compatible = "unittest-i2c-mux";
|
||||
status = "okay";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
i2c@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
test-mux-dev {
|
||||
reg = <32>;
|
||||
compatible = "unittest-i2c-dev";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/* overlay_2 - enable using label */
|
||||
|
||||
&unittest2 {
|
||||
status = "okay";
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/* overlay_3 - disable using label */
|
||||
|
||||
&unittest3 {
|
||||
status = "disabled";
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/* overlay_4 - test insertion of a full node */
|
||||
|
||||
&unittest_test_bus {
|
||||
|
||||
/* suppress DTC warning */
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
test-unittest4 {
|
||||
compatible = "unittest";
|
||||
status = "okay";
|
||||
reg = <4>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/* overlay_5 - test overlay apply revert */
|
||||
|
||||
&unittest5 {
|
||||
status = "okay";
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/* overlay_6 */
|
||||
/* overlays 6, 7 application and removal in sequence */
|
||||
|
||||
&unittest6 {
|
||||
status = "okay";
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/* overlay_7 */
|
||||
/* overlays 6, 7 application and removal in sequence */
|
||||
|
||||
&unittest7 {
|
||||
status = "okay";
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/* overlay_8 */
|
||||
/* overlays 8, 9, 10, 11 application and removal in bad sequence */
|
||||
|
||||
&unittest8 {
|
||||
status = "okay";
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/* overlay_9 */
|
||||
/* overlays 8, 9, 10, 11 application and removal in bad sequence */
|
||||
|
||||
&unittest8 {
|
||||
property-foo = "bar";
|
||||
};
|
|
@ -2,20 +2,13 @@
|
|||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/ {
|
||||
&electric_1 {
|
||||
|
||||
fragment@0 {
|
||||
target = <&electric_1>;
|
||||
|
||||
__overlay__ {
|
||||
|
||||
// This label should cause an error when the overlay
|
||||
// is applied. There is already a phandle value
|
||||
// in the base tree for motor-1.
|
||||
spin_ctrl_1_conflict: motor-1 {
|
||||
accelerate = < 3 >;
|
||||
decelerate = < 5 >;
|
||||
};
|
||||
};
|
||||
// This label should cause an error when the overlay
|
||||
// is applied. There is already a phandle value
|
||||
// in the base tree for motor-1.
|
||||
spin_ctrl_1_conflict: motor-1 {
|
||||
accelerate = < 3 >;
|
||||
decelerate = < 5 >;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -2,22 +2,15 @@
|
|||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/ {
|
||||
&electric_1 {
|
||||
|
||||
fragment@0 {
|
||||
target = <&electric_1>;
|
||||
|
||||
__overlay__ {
|
||||
|
||||
// This label should cause an error when the overlay
|
||||
// is applied. There is already a symbol hvac_1
|
||||
// in the base tree
|
||||
hvac_1: hvac-medium-2 {
|
||||
compatible = "ot,hvac-medium";
|
||||
heat-range = < 50 75 >;
|
||||
cool-range = < 60 80 >;
|
||||
};
|
||||
|
||||
};
|
||||
// This label should cause an error when the overlay
|
||||
// is applied. There is already a symbol hvac_1
|
||||
// in the base tree
|
||||
hvac_1: hvac-medium-2 {
|
||||
compatible = "ot,hvac-medium";
|
||||
heat-range = < 50 75 >;
|
||||
cool-range = < 60 80 >;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@ testcase-data {
|
|||
overlay-node {
|
||||
|
||||
/* test bus */
|
||||
unittestbus: test-bus {
|
||||
unittest_test_bus: test-bus {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
@ -70,7 +70,7 @@ unittest8: test-unittest8 {
|
|||
reg = <8>;
|
||||
};
|
||||
|
||||
i2c-test-bus {
|
||||
unittest_i2c_test_bus: i2c-test-bus {
|
||||
compatible = "unittest-i2c-bus";
|
||||
status = "okay";
|
||||
reg = <50>;
|
||||
|
@ -113,218 +113,5 @@ test-mux-dev {
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* test enable using absolute target path */
|
||||
overlay0 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/test-unittest0";
|
||||
__overlay__ {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* test disable using absolute target path */
|
||||
overlay1 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/test-unittest1";
|
||||
__overlay__ {
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* test enable using label */
|
||||
overlay2 {
|
||||
fragment@0 {
|
||||
target = <&unittest2>;
|
||||
__overlay__ {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* test disable using label */
|
||||
overlay3 {
|
||||
fragment@0 {
|
||||
target = <&unittest3>;
|
||||
__overlay__ {
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* test insertion of a full node */
|
||||
overlay4 {
|
||||
fragment@0 {
|
||||
target = <&unittestbus>;
|
||||
__overlay__ {
|
||||
|
||||
/* suppress DTC warning */
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
test-unittest4 {
|
||||
compatible = "unittest";
|
||||
status = "okay";
|
||||
reg = <4>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* test overlay apply revert */
|
||||
overlay5 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/test-unittest5";
|
||||
__overlay__ {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* test overlays application and removal in sequence */
|
||||
overlay6 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/test-unittest6";
|
||||
__overlay__ {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
overlay7 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/test-unittest7";
|
||||
__overlay__ {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* test overlays application and removal in bad sequence */
|
||||
overlay8 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/test-unittest8";
|
||||
__overlay__ {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
overlay9 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/test-unittest8";
|
||||
__overlay__ {
|
||||
property-foo = "bar";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
overlay10 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus";
|
||||
__overlay__ {
|
||||
|
||||
/* suppress DTC warning */
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
test-unittest10 {
|
||||
compatible = "unittest";
|
||||
status = "okay";
|
||||
reg = <10>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
test-unittest101 {
|
||||
compatible = "unittest";
|
||||
status = "okay";
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
overlay11 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus";
|
||||
__overlay__ {
|
||||
|
||||
/* suppress DTC warning */
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
test-unittest11 {
|
||||
compatible = "unittest";
|
||||
status = "okay";
|
||||
reg = <11>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
test-unittest111 {
|
||||
compatible = "unittest";
|
||||
status = "okay";
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* test enable using absolute target path (i2c) */
|
||||
overlay12 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12";
|
||||
__overlay__ {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* test disable using absolute target path (i2c) */
|
||||
overlay13 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13";
|
||||
__overlay__ {
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* test mux overlay */
|
||||
overlay15 {
|
||||
fragment@0 {
|
||||
target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus";
|
||||
__overlay__ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
test-unittest15 {
|
||||
reg = <11>;
|
||||
compatible = "unittest-i2c-mux";
|
||||
status = "okay";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
i2c@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
test-mux-dev {
|
||||
reg = <32>;
|
||||
compatible = "unittest-i2c-dev";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
|
|
@ -45,6 +45,8 @@ 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;
|
||||
|
@ -1116,8 +1118,7 @@ static int __init unittest_data_add(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* This lock normally encloses of_overlay_apply() as well as
|
||||
* of_resolve_phandles().
|
||||
* This lock normally encloses of_resolve_phandles()
|
||||
*/
|
||||
of_overlay_mutex_lock();
|
||||
|
||||
|
@ -1310,12 +1311,12 @@ static int of_unittest_device_exists(int unittest_nr, enum overlay_type ovtype)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *overlay_path(int nr)
|
||||
static const char *overlay_name_from_nr(int nr)
|
||||
{
|
||||
static char buf[256];
|
||||
|
||||
snprintf(buf, sizeof(buf) - 1,
|
||||
"/testcase-data/overlay%d", nr);
|
||||
"overlay_%d", nr);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
return buf;
|
||||
|
@ -1382,25 +1383,19 @@ static void of_unittest_destroy_tracked_overlays(void)
|
|||
} while (defers > 0);
|
||||
}
|
||||
|
||||
static int of_unittest_apply_overlay(int overlay_nr, int unittest_nr,
|
||||
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;
|
||||
|
||||
np = of_find_node_by_path(overlay_path(overlay_nr));
|
||||
if (np == NULL) {
|
||||
unittest(0, "could not find overlay node @\"%s\"\n",
|
||||
overlay_path(overlay_nr));
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
overlay_name = overlay_name_from_nr(overlay_nr);
|
||||
|
||||
*overlay_id = 0;
|
||||
ret = of_overlay_apply(np, overlay_id);
|
||||
if (ret < 0) {
|
||||
unittest(0, "could not create overlay from \"%s\"\n",
|
||||
overlay_path(overlay_nr));
|
||||
ret = overlay_data_apply(overlay_name, overlay_id);
|
||||
if (!ret) {
|
||||
unittest(0, "could not apply overlay \"%s\"\n",
|
||||
overlay_name);
|
||||
goto out;
|
||||
}
|
||||
of_unittest_track_overlay(*overlay_id);
|
||||
|
@ -1414,15 +1409,16 @@ static int of_unittest_apply_overlay(int overlay_nr, int unittest_nr,
|
|||
}
|
||||
|
||||
/* apply an overlay while checking before and after states */
|
||||
static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr,
|
||||
int before, int after, enum overlay_type ovtype)
|
||||
static int __init of_unittest_apply_overlay_check(int overlay_nr,
|
||||
int unittest_nr, int before, int after,
|
||||
enum overlay_type ovtype)
|
||||
{
|
||||
int ret, ovcs_id;
|
||||
|
||||
/* unittest device must not be in before state */
|
||||
if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
|
||||
unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
|
||||
overlay_path(overlay_nr),
|
||||
unittest(0, "%s with device @\"%s\" %s\n",
|
||||
overlay_name_from_nr(overlay_nr),
|
||||
unittest_path(unittest_nr, ovtype),
|
||||
!before ? "enabled" : "disabled");
|
||||
return -EINVAL;
|
||||
|
@ -1437,8 +1433,8 @@ static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr,
|
|||
|
||||
/* unittest device must be to set to after state */
|
||||
if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
|
||||
unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
|
||||
overlay_path(overlay_nr),
|
||||
unittest(0, "%s failed to create @\"%s\" %s\n",
|
||||
overlay_name_from_nr(overlay_nr),
|
||||
unittest_path(unittest_nr, ovtype),
|
||||
!after ? "enabled" : "disabled");
|
||||
return -EINVAL;
|
||||
|
@ -1448,7 +1444,7 @@ static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr,
|
|||
}
|
||||
|
||||
/* apply an overlay and then revert it while checking before, after states */
|
||||
static int of_unittest_apply_revert_overlay_check(int overlay_nr,
|
||||
static int __init of_unittest_apply_revert_overlay_check(int overlay_nr,
|
||||
int unittest_nr, int before, int after,
|
||||
enum overlay_type ovtype)
|
||||
{
|
||||
|
@ -1456,8 +1452,8 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
|
|||
|
||||
/* unittest device must be in before state */
|
||||
if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
|
||||
unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
|
||||
overlay_path(overlay_nr),
|
||||
unittest(0, "%s with device @\"%s\" %s\n",
|
||||
overlay_name_from_nr(overlay_nr),
|
||||
unittest_path(unittest_nr, ovtype),
|
||||
!before ? "enabled" : "disabled");
|
||||
return -EINVAL;
|
||||
|
@ -1473,8 +1469,8 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
|
|||
|
||||
/* unittest device must be in after state */
|
||||
if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
|
||||
unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
|
||||
overlay_path(overlay_nr),
|
||||
unittest(0, "%s failed to create @\"%s\" %s\n",
|
||||
overlay_name_from_nr(overlay_nr),
|
||||
unittest_path(unittest_nr, ovtype),
|
||||
!after ? "enabled" : "disabled");
|
||||
return -EINVAL;
|
||||
|
@ -1482,16 +1478,16 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
|
|||
|
||||
ret = of_overlay_remove(&ovcs_id);
|
||||
if (ret != 0) {
|
||||
unittest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n",
|
||||
overlay_path(overlay_nr),
|
||||
unittest(0, "%s failed to be destroyed @\"%s\"\n",
|
||||
overlay_name_from_nr(overlay_nr),
|
||||
unittest_path(unittest_nr, ovtype));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* unittest device must be again in before state */
|
||||
if (of_unittest_device_exists(unittest_nr, PDEV_OVERLAY) != before) {
|
||||
unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
|
||||
overlay_path(overlay_nr),
|
||||
unittest(0, "%s with device @\"%s\" %s\n",
|
||||
overlay_name_from_nr(overlay_nr),
|
||||
unittest_path(unittest_nr, ovtype),
|
||||
!before ? "enabled" : "disabled");
|
||||
return -EINVAL;
|
||||
|
@ -1501,7 +1497,7 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
|
|||
}
|
||||
|
||||
/* test activation of device */
|
||||
static void of_unittest_overlay_0(void)
|
||||
static void __init of_unittest_overlay_0(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -1514,7 +1510,7 @@ static void of_unittest_overlay_0(void)
|
|||
}
|
||||
|
||||
/* test deactivation of device */
|
||||
static void of_unittest_overlay_1(void)
|
||||
static void __init of_unittest_overlay_1(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -1527,7 +1523,7 @@ static void of_unittest_overlay_1(void)
|
|||
}
|
||||
|
||||
/* test activation of device */
|
||||
static void of_unittest_overlay_2(void)
|
||||
static void __init of_unittest_overlay_2(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -1540,7 +1536,7 @@ static void of_unittest_overlay_2(void)
|
|||
}
|
||||
|
||||
/* test deactivation of device */
|
||||
static void of_unittest_overlay_3(void)
|
||||
static void __init of_unittest_overlay_3(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -1553,7 +1549,7 @@ static void of_unittest_overlay_3(void)
|
|||
}
|
||||
|
||||
/* test activation of a full device node */
|
||||
static void of_unittest_overlay_4(void)
|
||||
static void __init of_unittest_overlay_4(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -1566,7 +1562,7 @@ static void of_unittest_overlay_4(void)
|
|||
}
|
||||
|
||||
/* test overlay apply/revert sequence */
|
||||
static void of_unittest_overlay_5(void)
|
||||
static void __init of_unittest_overlay_5(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -1579,19 +1575,19 @@ static void of_unittest_overlay_5(void)
|
|||
}
|
||||
|
||||
/* test overlay application in sequence */
|
||||
static void of_unittest_overlay_6(void)
|
||||
static void __init of_unittest_overlay_6(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
int ret, i, ov_id[2], ovcs_id;
|
||||
int overlay_nr = 6, unittest_nr = 6;
|
||||
int before = 0, after = 1;
|
||||
const char *overlay_name;
|
||||
|
||||
/* unittest device must be in before state */
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
|
||||
!= before) {
|
||||
unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
|
||||
overlay_path(overlay_nr + i),
|
||||
unittest(0, "%s with device @\"%s\" %s\n",
|
||||
overlay_name_from_nr(overlay_nr + i),
|
||||
unittest_path(unittest_nr + i,
|
||||
PDEV_OVERLAY),
|
||||
!before ? "enabled" : "disabled");
|
||||
|
@ -1602,18 +1598,12 @@ static void of_unittest_overlay_6(void)
|
|||
/* apply the overlays */
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
||||
np = of_find_node_by_path(overlay_path(overlay_nr + i));
|
||||
if (np == NULL) {
|
||||
unittest(0, "could not find overlay node @\"%s\"\n",
|
||||
overlay_path(overlay_nr + i));
|
||||
return;
|
||||
}
|
||||
overlay_name = overlay_name_from_nr(overlay_nr + i);
|
||||
|
||||
ovcs_id = 0;
|
||||
ret = of_overlay_apply(np, &ovcs_id);
|
||||
if (ret < 0) {
|
||||
unittest(0, "could not create overlay from \"%s\"\n",
|
||||
overlay_path(overlay_nr + i));
|
||||
ret = overlay_data_apply(overlay_name, &ovcs_id);
|
||||
if (!ret) {
|
||||
unittest(0, "could not apply overlay \"%s\"\n",
|
||||
overlay_name);
|
||||
return;
|
||||
}
|
||||
ov_id[i] = ovcs_id;
|
||||
|
@ -1625,7 +1615,7 @@ static void of_unittest_overlay_6(void)
|
|||
if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
|
||||
!= after) {
|
||||
unittest(0, "overlay @\"%s\" failed @\"%s\" %s\n",
|
||||
overlay_path(overlay_nr + i),
|
||||
overlay_name_from_nr(overlay_nr + i),
|
||||
unittest_path(unittest_nr + i,
|
||||
PDEV_OVERLAY),
|
||||
!after ? "enabled" : "disabled");
|
||||
|
@ -1637,8 +1627,8 @@ static void of_unittest_overlay_6(void)
|
|||
ovcs_id = ov_id[i];
|
||||
ret = of_overlay_remove(&ovcs_id);
|
||||
if (ret != 0) {
|
||||
unittest(0, "overlay @\"%s\" failed destroy @\"%s\"\n",
|
||||
overlay_path(overlay_nr + i),
|
||||
unittest(0, "%s failed destroy @\"%s\"\n",
|
||||
overlay_name_from_nr(overlay_nr + i),
|
||||
unittest_path(unittest_nr + i,
|
||||
PDEV_OVERLAY));
|
||||
return;
|
||||
|
@ -1650,8 +1640,8 @@ static void of_unittest_overlay_6(void)
|
|||
/* unittest device must be again in before state */
|
||||
if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
|
||||
!= before) {
|
||||
unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
|
||||
overlay_path(overlay_nr + i),
|
||||
unittest(0, "%s with device @\"%s\" %s\n",
|
||||
overlay_name_from_nr(overlay_nr + i),
|
||||
unittest_path(unittest_nr + i,
|
||||
PDEV_OVERLAY),
|
||||
!before ? "enabled" : "disabled");
|
||||
|
@ -1663,29 +1653,23 @@ static void of_unittest_overlay_6(void)
|
|||
}
|
||||
|
||||
/* test overlay application in sequence */
|
||||
static void of_unittest_overlay_8(void)
|
||||
static void __init of_unittest_overlay_8(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
int ret, i, ov_id[2], ovcs_id;
|
||||
int overlay_nr = 8, unittest_nr = 8;
|
||||
const char *overlay_name;
|
||||
|
||||
/* we don't care about device state in this test */
|
||||
|
||||
/* apply the overlays */
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
||||
np = of_find_node_by_path(overlay_path(overlay_nr + i));
|
||||
if (np == NULL) {
|
||||
unittest(0, "could not find overlay node @\"%s\"\n",
|
||||
overlay_path(overlay_nr + i));
|
||||
return;
|
||||
}
|
||||
overlay_name = overlay_name_from_nr(overlay_nr + i);
|
||||
|
||||
ovcs_id = 0;
|
||||
ret = of_overlay_apply(np, &ovcs_id);
|
||||
ret = overlay_data_apply(overlay_name, &ovcs_id);
|
||||
if (ret < 0) {
|
||||
unittest(0, "could not create overlay from \"%s\"\n",
|
||||
overlay_path(overlay_nr + i));
|
||||
unittest(0, "could not apply overlay \"%s\"\n",
|
||||
overlay_name);
|
||||
return;
|
||||
}
|
||||
ov_id[i] = ovcs_id;
|
||||
|
@ -1696,8 +1680,8 @@ static void of_unittest_overlay_8(void)
|
|||
ovcs_id = ov_id[0];
|
||||
ret = of_overlay_remove(&ovcs_id);
|
||||
if (ret == 0) {
|
||||
unittest(0, "overlay @\"%s\" was destroyed @\"%s\"\n",
|
||||
overlay_path(overlay_nr + 0),
|
||||
unittest(0, "%s was destroyed @\"%s\"\n",
|
||||
overlay_name_from_nr(overlay_nr + 0),
|
||||
unittest_path(unittest_nr,
|
||||
PDEV_OVERLAY));
|
||||
return;
|
||||
|
@ -1708,8 +1692,8 @@ static void of_unittest_overlay_8(void)
|
|||
ovcs_id = ov_id[i];
|
||||
ret = of_overlay_remove(&ovcs_id);
|
||||
if (ret != 0) {
|
||||
unittest(0, "overlay @\"%s\" not destroyed @\"%s\"\n",
|
||||
overlay_path(overlay_nr + i),
|
||||
unittest(0, "%s not destroyed @\"%s\"\n",
|
||||
overlay_name_from_nr(overlay_nr + i),
|
||||
unittest_path(unittest_nr,
|
||||
PDEV_OVERLAY));
|
||||
return;
|
||||
|
@ -1721,7 +1705,7 @@ static void of_unittest_overlay_8(void)
|
|||
}
|
||||
|
||||
/* test insertion of a bus with parent devices */
|
||||
static void of_unittest_overlay_10(void)
|
||||
static void __init of_unittest_overlay_10(void)
|
||||
{
|
||||
int ret;
|
||||
char *child_path;
|
||||
|
@ -1744,7 +1728,7 @@ static void of_unittest_overlay_10(void)
|
|||
}
|
||||
|
||||
/* test insertion of a bus with parent devices (and revert) */
|
||||
static void of_unittest_overlay_11(void)
|
||||
static void __init of_unittest_overlay_11(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -2010,7 +1994,7 @@ static void of_unittest_overlay_i2c_cleanup(void)
|
|||
i2c_del_driver(&unittest_i2c_dev_driver);
|
||||
}
|
||||
|
||||
static void of_unittest_overlay_i2c_12(void)
|
||||
static void __init of_unittest_overlay_i2c_12(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -2023,7 +2007,7 @@ static void of_unittest_overlay_i2c_12(void)
|
|||
}
|
||||
|
||||
/* test deactivation of device */
|
||||
static void of_unittest_overlay_i2c_13(void)
|
||||
static void __init of_unittest_overlay_i2c_13(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -2040,7 +2024,7 @@ static void of_unittest_overlay_i2c_14(void)
|
|||
{
|
||||
}
|
||||
|
||||
static void of_unittest_overlay_i2c_15(void)
|
||||
static void __init of_unittest_overlay_i2c_15(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -2142,23 +2126,38 @@ static inline void __init of_unittest_overlay(void) { }
|
|||
extern uint8_t __dtb_##name##_begin[]; \
|
||||
extern uint8_t __dtb_##name##_end[]
|
||||
|
||||
#define OVERLAY_INFO(name, expected) \
|
||||
{ .dtb_begin = __dtb_##name##_begin, \
|
||||
.dtb_end = __dtb_##name##_end, \
|
||||
.expected_result = expected, \
|
||||
#define OVERLAY_INFO(overlay_name, expected) \
|
||||
{ .dtb_begin = __dtb_##overlay_name##_begin, \
|
||||
.dtb_end = __dtb_##overlay_name##_end, \
|
||||
.expected_result = expected, \
|
||||
.name = #overlay_name, \
|
||||
}
|
||||
|
||||
struct overlay_info {
|
||||
uint8_t *dtb_begin;
|
||||
uint8_t *dtb_end;
|
||||
void *data;
|
||||
struct device_node *np_overlay;
|
||||
int expected_result;
|
||||
int overlay_id;
|
||||
uint8_t *dtb_begin;
|
||||
uint8_t *dtb_end;
|
||||
int expected_result;
|
||||
int overlay_id;
|
||||
char *name;
|
||||
};
|
||||
|
||||
OVERLAY_INFO_EXTERN(overlay_base);
|
||||
OVERLAY_INFO_EXTERN(overlay);
|
||||
OVERLAY_INFO_EXTERN(overlay_0);
|
||||
OVERLAY_INFO_EXTERN(overlay_1);
|
||||
OVERLAY_INFO_EXTERN(overlay_2);
|
||||
OVERLAY_INFO_EXTERN(overlay_3);
|
||||
OVERLAY_INFO_EXTERN(overlay_4);
|
||||
OVERLAY_INFO_EXTERN(overlay_5);
|
||||
OVERLAY_INFO_EXTERN(overlay_6);
|
||||
OVERLAY_INFO_EXTERN(overlay_7);
|
||||
OVERLAY_INFO_EXTERN(overlay_8);
|
||||
OVERLAY_INFO_EXTERN(overlay_9);
|
||||
OVERLAY_INFO_EXTERN(overlay_10);
|
||||
OVERLAY_INFO_EXTERN(overlay_11);
|
||||
OVERLAY_INFO_EXTERN(overlay_12);
|
||||
OVERLAY_INFO_EXTERN(overlay_13);
|
||||
OVERLAY_INFO_EXTERN(overlay_15);
|
||||
OVERLAY_INFO_EXTERN(overlay_bad_phandle);
|
||||
OVERLAY_INFO_EXTERN(overlay_bad_symbol);
|
||||
|
||||
|
@ -2166,6 +2165,21 @@ OVERLAY_INFO_EXTERN(overlay_bad_symbol);
|
|||
static struct overlay_info overlays[] = {
|
||||
OVERLAY_INFO(overlay_base, -9999),
|
||||
OVERLAY_INFO(overlay, 0),
|
||||
OVERLAY_INFO(overlay_0, 0),
|
||||
OVERLAY_INFO(overlay_1, 0),
|
||||
OVERLAY_INFO(overlay_2, 0),
|
||||
OVERLAY_INFO(overlay_3, 0),
|
||||
OVERLAY_INFO(overlay_4, 0),
|
||||
OVERLAY_INFO(overlay_5, 0),
|
||||
OVERLAY_INFO(overlay_6, 0),
|
||||
OVERLAY_INFO(overlay_7, 0),
|
||||
OVERLAY_INFO(overlay_8, 0),
|
||||
OVERLAY_INFO(overlay_9, 0),
|
||||
OVERLAY_INFO(overlay_10, 0),
|
||||
OVERLAY_INFO(overlay_11, 0),
|
||||
OVERLAY_INFO(overlay_12, 0),
|
||||
OVERLAY_INFO(overlay_13, 0),
|
||||
OVERLAY_INFO(overlay_15, 0),
|
||||
OVERLAY_INFO(overlay_bad_phandle, -EINVAL),
|
||||
OVERLAY_INFO(overlay_bad_symbol, -EINVAL),
|
||||
{}
|
||||
|
@ -2196,6 +2210,7 @@ void __init unittest_unflatten_overlay_base(void)
|
|||
{
|
||||
struct overlay_info *info;
|
||||
u32 data_size;
|
||||
void *new_fdt;
|
||||
u32 size;
|
||||
|
||||
info = &overlays[0];
|
||||
|
@ -2217,17 +2232,16 @@ void __init unittest_unflatten_overlay_base(void)
|
|||
return;
|
||||
}
|
||||
|
||||
info->data = dt_alloc_memory(size, roundup_pow_of_two(FDT_V17_SIZE));
|
||||
if (!info->data) {
|
||||
new_fdt = dt_alloc_memory(size, roundup_pow_of_two(FDT_V17_SIZE));
|
||||
if (!new_fdt) {
|
||||
pr_err("alloc for dtb 'overlay_base' failed");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(info->data, info->dtb_begin, size);
|
||||
memcpy(new_fdt, info->dtb_begin, size);
|
||||
|
||||
__unflatten_device_tree(info->data, NULL, &info->np_overlay,
|
||||
__unflatten_device_tree(new_fdt, NULL, &overlay_base_root,
|
||||
dt_alloc_memory, true);
|
||||
overlay_base_root = info->np_overlay;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2241,73 +2255,44 @@ void __init unittest_unflatten_overlay_base(void)
|
|||
*
|
||||
* Return 0 on unexpected error.
|
||||
*/
|
||||
static int __init overlay_data_add(int onum)
|
||||
static int __init overlay_data_apply(const char *overlay_name, int *overlay_id)
|
||||
{
|
||||
struct overlay_info *info;
|
||||
int found = 0;
|
||||
int k;
|
||||
int ret;
|
||||
u32 size;
|
||||
u32 size_from_header;
|
||||
|
||||
for (k = 0, info = overlays; info; info++, k++) {
|
||||
if (k == onum)
|
||||
for (k = 0, info = overlays; info && info->name; info++, k++) {
|
||||
if (!strcmp(overlay_name, info->name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (onum > k)
|
||||
if (!found) {
|
||||
pr_err("no overlay data for %s\n", overlay_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = info->dtb_end - info->dtb_begin;
|
||||
if (!size) {
|
||||
pr_err("no overlay to attach, %d\n", onum);
|
||||
pr_err("no overlay data for %s\n", overlay_name);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
size_from_header = fdt_totalsize(info->dtb_begin);
|
||||
if (size_from_header != size) {
|
||||
pr_err("overlay header totalsize != actual size, %d", onum);
|
||||
return 0;
|
||||
}
|
||||
ret = of_overlay_fdt_apply(info->dtb_begin, size, &info->overlay_id);
|
||||
if (overlay_id)
|
||||
*overlay_id = info->overlay_id;
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Must create permanent copy of FDT because of_fdt_unflatten_tree()
|
||||
* will create pointers to the passed in FDT in the EDT.
|
||||
*/
|
||||
info->data = kmemdup(info->dtb_begin, size, GFP_KERNEL);
|
||||
if (!info->data) {
|
||||
pr_err("unable to allocate memory for data, %d\n", onum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
of_fdt_unflatten_tree(info->data, NULL, &info->np_overlay);
|
||||
if (!info->np_overlay) {
|
||||
pr_err("unable to unflatten overlay, %d\n", onum);
|
||||
ret = 0;
|
||||
goto out_free_data;
|
||||
}
|
||||
|
||||
info->overlay_id = 0;
|
||||
ret = of_overlay_apply(info->np_overlay, &info->overlay_id);
|
||||
if (ret < 0) {
|
||||
pr_err("of_overlay_apply() (ret=%d), %d\n", ret, onum);
|
||||
goto out_free_np_overlay;
|
||||
}
|
||||
|
||||
pr_debug("__dtb_overlay_begin applied, overlay id %d\n", ret);
|
||||
|
||||
goto out;
|
||||
|
||||
out_free_np_overlay:
|
||||
/*
|
||||
* info->np_overlay is the unflattened device tree
|
||||
* It has not been spliced into the live tree.
|
||||
*/
|
||||
|
||||
/* todo: function to free unflattened device tree */
|
||||
|
||||
out_free_data:
|
||||
kfree(info->data);
|
||||
pr_debug("%s applied\n", overlay_name);
|
||||
|
||||
out:
|
||||
if (ret != info->expected_result)
|
||||
pr_err("of_overlay_fdt_apply() expected %d, ret=%d, %s\n",
|
||||
info->expected_result, ret, overlay_name);
|
||||
|
||||
return (ret == info->expected_result);
|
||||
}
|
||||
|
||||
|
@ -2409,18 +2394,29 @@ static __init void of_unittest_overlay_high_level(void)
|
|||
__of_attach_node_sysfs(np);
|
||||
|
||||
if (of_symbols) {
|
||||
struct property *new_prop;
|
||||
for_each_property_of_node(overlay_base_symbols, prop) {
|
||||
ret = __of_add_property(of_symbols, prop);
|
||||
if (ret) {
|
||||
unittest(0,
|
||||
"duplicate property '%s' in overlay_base node __symbols__",
|
||||
|
||||
new_prop = __of_prop_dup(prop, GFP_KERNEL);
|
||||
if (!new_prop) {
|
||||
unittest(0, "__of_prop_dup() of '%s' from overlay_base node __symbols__",
|
||||
prop->name);
|
||||
goto err_unlock;
|
||||
}
|
||||
ret = __of_add_property_sysfs(of_symbols, prop);
|
||||
ret = __of_add_property(of_symbols, new_prop);
|
||||
if (ret) {
|
||||
unittest(0,
|
||||
"unable to add property '%s' in overlay_base node __symbols__ to sysfs",
|
||||
if (!strcmp(new_prop->name, "name")) {
|
||||
/* auto-generated by unflatten */
|
||||
ret = 0;
|
||||
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) {
|
||||
unittest(0, "unable to add property '%s' in overlay_base node __symbols__ to sysfs",
|
||||
prop->name);
|
||||
goto err_unlock;
|
||||
}
|
||||
|
@ -2432,13 +2428,13 @@ static __init void of_unittest_overlay_high_level(void)
|
|||
|
||||
/* now do the normal overlay usage test */
|
||||
|
||||
unittest(overlay_data_add(1),
|
||||
unittest(overlay_data_apply("overlay", NULL),
|
||||
"Adding overlay 'overlay' failed\n");
|
||||
|
||||
unittest(overlay_data_add(2),
|
||||
unittest(overlay_data_apply("overlay_bad_phandle", NULL),
|
||||
"Adding overlay 'overlay_bad_phandle' failed\n");
|
||||
|
||||
unittest(overlay_data_add(3),
|
||||
unittest(overlay_data_apply("overlay_bad_symbol", NULL),
|
||||
"Adding overlay 'overlay_bad_symbol' failed\n");
|
||||
|
||||
return;
|
||||
|
|
|
@ -1371,8 +1371,8 @@ struct of_overlay_notify_data {
|
|||
|
||||
#ifdef CONFIG_OF_OVERLAY
|
||||
|
||||
/* ID based overlays; the API for external users */
|
||||
int of_overlay_apply(struct device_node *tree, int *ovcs_id);
|
||||
int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
|
||||
int *ovcs_id);
|
||||
int of_overlay_remove(int *ovcs_id);
|
||||
int of_overlay_remove_all(void);
|
||||
|
||||
|
@ -1381,7 +1381,7 @@ int of_overlay_notifier_unregister(struct notifier_block *nb);
|
|||
|
||||
#else
|
||||
|
||||
static inline int of_overlay_apply(struct device_node *tree, int *ovcs_id)
|
||||
static inline int of_overlay_fdt_apply(void *overlay_fdt, int *ovcs_id)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue