Re: [PATCH v3] Adding selftest testdata dynamically into live tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Wed, 16 Jul 2014 23:09:39 -0700, Gaurav Minocha <gaurav.minocha.os@xxxxxxxxx> 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 <gaurav.minocha.os@xxxxxxxxx>

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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux