On Wed, 16 Jul 2014 23:09:39 -0700, Gaurav Minocha
<[email protected]> wrote:
> This patch attaches selftest's device tree data (required by
> /drivers/of/selftest.c)
> dynamically into live device tree. First, it links selftest device tree data
> into the
> kernel image and then iterates over all the nodes and attaches them into the
> live tree.
> Once the testcases are complete, it removes the data attached.
>
> This patch will remove the manual process of addition and removal of selftest
> device
> tree data into the machine's dts file. Also, it can be build as a loadable
> kernel
> module by setting the config symbol OF_SELFTEST=m.
>
> Tested successfully with current selftest's testcases.
>
> Signed-off-by: Gaurav Minocha <[email protected]>
Merged, thanks. I've run tested on QEMU PowerPC pseries and ARM
Versatile Express models. One of the testcases fails on powerpc, but
that is a problem with the testcase itself, and not with this code.
g.
> ---
> arch/arm/boot/dts/versatile-pb.dts | 2 -
> drivers/of/Kconfig | 3 +-
> drivers/of/Makefile | 3 +-
> drivers/of/base.c | 5 +
> drivers/of/platform.c | 1 +
> drivers/of/selftest.c | 157
> ++++++++++++++++++++
> .../{testcases.dtsi => testcases.dts} | 1 +
> 7 files changed, 168 insertions(+), 4 deletions(-)
> rename drivers/of/testcase-data/{testcases.dtsi => testcases.dts} (92%)
>
> diff --git a/arch/arm/boot/dts/versatile-pb.dts
> b/arch/arm/boot/dts/versatile-pb.dts
> index 65f6577..8d39677 100644
> --- a/arch/arm/boot/dts/versatile-pb.dts
> +++ b/arch/arm/boot/dts/versatile-pb.dts
> @@ -46,5 +46,3 @@
> };
> };
> };
> -
> -#include <testcases.dtsi>
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index 2dcb054..4e4f6f3 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -8,8 +8,9 @@ menu "Device Tree and Open Firmware support"
> depends on OF
>
> config OF_SELFTEST
> - bool "Device Tree Runtime self tests"
> + tristate "Device Tree Runtime self tests"
> depends on OF_IRQ
> + select OF_DYNAMIC
> help
> This option builds in test cases for the device tree infrastructure
> that are executed once at boot time, and the results dumped to the
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index 099b1fb..b9e753b 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -5,7 +5,8 @@ obj-$(CONFIG_OF_PROMTREE) += pdt.o
> obj-$(CONFIG_OF_ADDRESS) += address.o
> obj-$(CONFIG_OF_IRQ) += irq.o
> obj-$(CONFIG_OF_NET) += of_net.o
> -obj-$(CONFIG_OF_SELFTEST) += selftest.o
> +obj-$(CONFIG_OF_SELFTEST) += of_selftest.o
> +of_selftest-objs := selftest.o testcase-data/testcases.dtb.o
> obj-$(CONFIG_OF_MDIO) += of_mdio.o
> obj-$(CONFIG_OF_PCI) += of_pci.o
> obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index b986480..b47c1d8 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -1814,6 +1814,7 @@ int of_add_property(struct device_node *np, struct
> property *prop)
>
> return rc;
> }
> +EXPORT_SYMBOL(of_add_property);
>
> /**
> * of_remove_property - Remove a property from a node.
> @@ -1860,6 +1861,7 @@ int of_remove_property(struct device_node *np, struct
> property *prop)
>
> return 0;
> }
> +EXPORT_SYMBOL(of_remove_property);
>
> /*
> * of_update_property - Update a property in a node, if the property does
> @@ -1915,6 +1917,7 @@ int of_update_property(struct device_node *np, struct
> property *newprop)
>
> return 0;
> }
> +EXPORT_SYMBOL(of_update_property);
>
> #if defined(CONFIG_OF_DYNAMIC)
> /*
> @@ -1970,6 +1973,7 @@ int of_attach_node(struct device_node *np)
> of_node_add(np);
> return 0;
> }
> +EXPORT_SYMBOL(of_attach_node);
>
> /**
> * of_detach_node - "Unplug" a node from the device tree.
> @@ -2029,6 +2033,7 @@ int of_detach_node(struct device_node *np)
> of_node_remove(np);
> return rc;
> }
> +EXPORT_SYMBOL(of_detach_node);
> #endif /* defined(CONFIG_OF_DYNAMIC) */
>
> static void of_alias_add(struct alias_prop *ap, struct device_node *np,
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index 500436f..b7a82d6 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -30,6 +30,7 @@ const struct of_device_id of_default_bus_match_table[] = {
> #endif /* CONFIG_ARM_AMBA */
> {} /* Empty terminated list */
> };
> +EXPORT_SYMBOL(of_default_bus_match_table);
>
> static int of_dev_node_match(struct device *dev, void *data)
> {
> diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
> index 077314e..3a1c5b5 100644
> --- a/drivers/of/selftest.c
> +++ b/drivers/of/selftest.c
> @@ -9,6 +9,7 @@
> #include <linux/errno.h>
> #include <linux/module.h>
> #include <linux/of.h>
> +#include <linux/of_fdt.h>
> #include <linux/of_irq.h>
> #include <linux/of_platform.h>
> #include <linux/list.h>
> @@ -21,6 +22,10 @@ static struct selftest_results {
> int failed;
> } selftest_results;
>
> +#define NO_OF_NODES 2
> +static struct device_node *nodes[NO_OF_NODES];
> +static int last_node_index;
> +
> #define selftest(result, fmt, ...) { \
> if (!(result)) { \
> selftest_results.failed++; \
> @@ -517,9 +522,156 @@ static void __init of_selftest_platform_populate(void)
> }
> }
>
> +/**
> + * update_node_properties - adds the properties
> + * of np into dup node (present in live tree) and
> + * updates parent of children of np to dup.
> + *
> + * @np: node already present in live tree
> + * @dup: node present in live tree to be updated
> + */
> +static void update_node_properties(struct device_node *np,
> + struct device_node *dup)
> +{
> + struct property *prop;
> + struct device_node *child;
> +
> + for_each_property_of_node(np, prop)
> + of_add_property(dup, prop);
> +
> + for_each_child_of_node(np, child)
> + child->parent = dup;
> +}
> +
> +/**
> + * attach_node_and_children - attaches nodes
> + * and its children to live tree
> + *
> + * @np: Node to attach to live tree
> + */
> +static int attach_node_and_children(struct device_node *np)
> +{
> + struct device_node *next, *root = np, *dup;
> +
> + if (!np) {
> + pr_warn("%s: No tree to attach; not running tests\n",
> + __func__);
> + return -ENODATA;
> + }
> +
> +
> + /* skip root node */
> + np = np->child;
> + /* storing a copy in temporary node */
> + dup = np;
> +
> + while (dup) {
> + nodes[last_node_index++] = dup;
> + dup = dup->sibling;
> + }
> + dup = NULL;
> +
> + while (np) {
> + next = np->allnext;
> + dup = of_find_node_by_path(np->full_name);
> + if (dup)
> + update_node_properties(np, dup);
> + else {
> + np->child = NULL;
> + if (np->parent == root)
> + np->parent = of_allnodes;
> + of_attach_node(np);
> + }
> + np = next;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * selftest_data_add - Reads, copies data from
> + * linked tree and attaches it to the live tree
> + */
> +static int __init selftest_data_add(void)
> +{
> + void *selftest_data;
> + struct device_node *selftest_data_node;
> + extern uint8_t __dtb_testcases_begin[];
> + extern uint8_t __dtb_testcases_end[];
> + const int size = __dtb_testcases_end - __dtb_testcases_begin;
> +
> + if (!size) {
> + pr_warn("%s: No testcase data to attach; not running tests\n",
> + __func__);
> + return -ENODATA;
> + }
> +
> + /* creating copy */
> + selftest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL);
> +
> + if (!selftest_data) {
> + pr_warn("%s: Failed to allocate memory for selftest_data; "
> + "not running tests\n", __func__);
> + return -ENOMEM;
> + }
> + of_fdt_unflatten_tree(selftest_data, &selftest_data_node);
> +
> + /* attach the sub-tree to live tree */
> + return attach_node_and_children(selftest_data_node);
> +}
> +
> +/**
> + * detach_node_and_children - detaches node
> + * and its children from live tree
> + *
> + * @np: Node to detach from live tree
> + */
> +static void detach_node_and_children(struct device_node *np)
> +{
> + while (np->child)
> + detach_node_and_children(np->child);
> +
> + while (np->sibling)
> + detach_node_and_children(np->sibling);
> +
> + of_detach_node(np);
> +}
> +
> +/**
> + * selftest_data_remove - removes the selftest data
> + * nodes from the live tree
> + */
> +static void selftest_data_remove(void)
> +{
> + struct device_node *np;
> + struct property *prop;
> +
> + while (last_node_index >= 0) {
> + if (nodes[last_node_index]) {
> + np =
> of_find_node_by_path(nodes[last_node_index]->full_name);
> + if (strcmp(np->full_name, "/aliases") != 0) {
> + detach_node_and_children(np->child);
> + of_detach_node(np);
> + } else {
> + for_each_property_of_node(np, prop) {
> + if (strcmp(prop->name,
> "testcase-alias") == 0)
> + of_remove_property(np, prop);
> + }
> + }
> + }
> + last_node_index--;
> + }
> +}
> +
> static int __init of_selftest(void)
> {
> struct device_node *np;
> + int res;
> +
> + /* adding data for selftest */
> + res = selftest_data_add();
> + if (res)
> + return res;
>
> np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
> if (!np) {
> @@ -539,6 +691,11 @@ static int __init of_selftest(void)
> of_selftest_platform_populate();
> pr_info("end of selftest - %i passed, %i failed\n",
> selftest_results.passed, selftest_results.failed);
> +
> + /* removing selftest data from live tree */
> + selftest_data_remove();
> +
> return 0;
> }
> late_initcall(of_selftest);
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/of/testcase-data/testcases.dtsi
> b/drivers/of/testcase-data/testcases.dts
> similarity index 92%
> rename from drivers/of/testcase-data/testcases.dtsi
> rename to drivers/of/testcase-data/testcases.dts
> index 6d8d980a..8e7568e 100644
> --- a/drivers/of/testcase-data/testcases.dtsi
> +++ b/drivers/of/testcase-data/testcases.dts
> @@ -1,3 +1,4 @@
> +/dts-v1/;
> #include "tests-phandle.dtsi"
> #include "tests-interrupts.dtsi"
> #include "tests-match.dtsi"
> --
> 1.7.9.5
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html