Skip to content

Commit ae9304c

Browse files
gauravminochaosglikely
authored andcommitted
Adding selftest testdata dynamically into live tree
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. Tested successfully with current selftest's testcases. Signed-off-by: Gaurav Minocha <[email protected]> [glikely: Removed ability to build as a module and fixed no-devicetree bug] Signed-off-by: Grant Likely <[email protected]>
1 parent 848007b commit ae9304c

File tree

5 files changed

+160
-3
lines changed

5 files changed

+160
-3
lines changed

arch/arm/boot/dts/versatile-pb.dts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,3 @@
4646
};
4747
};
4848
};
49-
50-
#include <testcases.dtsi>

drivers/of/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ menu "Device Tree and Open Firmware support"
1010
config OF_SELFTEST
1111
bool "Device Tree Runtime self tests"
1212
depends on OF_IRQ
13+
select OF_DYNAMIC
1314
help
1415
This option builds in test cases for the device tree infrastructure
1516
that are executed once at boot time, and the results dumped to the

drivers/of/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ obj-$(CONFIG_OF_PROMTREE) += pdt.o
55
obj-$(CONFIG_OF_ADDRESS) += address.o
66
obj-$(CONFIG_OF_IRQ) += irq.o
77
obj-$(CONFIG_OF_NET) += of_net.o
8-
obj-$(CONFIG_OF_SELFTEST) += selftest.o
8+
obj-$(CONFIG_OF_SELFTEST) += of_selftest.o
9+
of_selftest-objs := selftest.o testcase-data/testcases.dtb.o
910
obj-$(CONFIG_OF_MDIO) += of_mdio.o
1011
obj-$(CONFIG_OF_PCI) += of_pci.o
1112
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o

drivers/of/selftest.c

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/errno.h>
1010
#include <linux/module.h>
1111
#include <linux/of.h>
12+
#include <linux/of_fdt.h>
1213
#include <linux/of_irq.h>
1314
#include <linux/of_platform.h>
1415
#include <linux/list.h>
@@ -21,6 +22,10 @@ static struct selftest_results {
2122
int failed;
2223
} selftest_results;
2324

25+
#define NO_OF_NODES 2
26+
static struct device_node *nodes[NO_OF_NODES];
27+
static int last_node_index;
28+
2429
#define selftest(result, fmt, ...) { \
2530
if (!(result)) { \
2631
selftest_results.failed++; \
@@ -517,9 +522,156 @@ static void __init of_selftest_platform_populate(void)
517522
}
518523
}
519524

525+
/**
526+
* update_node_properties - adds the properties
527+
* of np into dup node (present in live tree) and
528+
* updates parent of children of np to dup.
529+
*
530+
* @np: node already present in live tree
531+
* @dup: node present in live tree to be updated
532+
*/
533+
static void update_node_properties(struct device_node *np,
534+
struct device_node *dup)
535+
{
536+
struct property *prop;
537+
struct device_node *child;
538+
539+
for_each_property_of_node(np, prop)
540+
of_add_property(dup, prop);
541+
542+
for_each_child_of_node(np, child)
543+
child->parent = dup;
544+
}
545+
546+
/**
547+
* attach_node_and_children - attaches nodes
548+
* and its children to live tree
549+
*
550+
* @np: Node to attach to live tree
551+
*/
552+
static int attach_node_and_children(struct device_node *np)
553+
{
554+
struct device_node *next, *root = np, *dup;
555+
556+
if (!np) {
557+
pr_warn("%s: No tree to attach; not running tests\n",
558+
__func__);
559+
return -ENODATA;
560+
}
561+
562+
563+
/* skip root node */
564+
np = np->child;
565+
/* storing a copy in temporary node */
566+
dup = np;
567+
568+
while (dup) {
569+
nodes[last_node_index++] = dup;
570+
dup = dup->sibling;
571+
}
572+
dup = NULL;
573+
574+
while (np) {
575+
next = np->allnext;
576+
dup = of_find_node_by_path(np->full_name);
577+
if (dup)
578+
update_node_properties(np, dup);
579+
else {
580+
np->child = NULL;
581+
if (np->parent == root)
582+
np->parent = of_allnodes;
583+
of_attach_node(np);
584+
}
585+
np = next;
586+
}
587+
588+
return 0;
589+
}
590+
591+
/**
592+
* selftest_data_add - Reads, copies data from
593+
* linked tree and attaches it to the live tree
594+
*/
595+
static int __init selftest_data_add(void)
596+
{
597+
void *selftest_data;
598+
struct device_node *selftest_data_node;
599+
extern uint8_t __dtb_testcases_begin[];
600+
extern uint8_t __dtb_testcases_end[];
601+
const int size = __dtb_testcases_end - __dtb_testcases_begin;
602+
603+
if (!size || !of_allnodes) {
604+
pr_warn("%s: No testcase data to attach; not running tests\n",
605+
__func__);
606+
return -ENODATA;
607+
}
608+
609+
/* creating copy */
610+
selftest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL);
611+
612+
if (!selftest_data) {
613+
pr_warn("%s: Failed to allocate memory for selftest_data; "
614+
"not running tests\n", __func__);
615+
return -ENOMEM;
616+
}
617+
of_fdt_unflatten_tree(selftest_data, &selftest_data_node);
618+
619+
/* attach the sub-tree to live tree */
620+
return attach_node_and_children(selftest_data_node);
621+
}
622+
623+
/**
624+
* detach_node_and_children - detaches node
625+
* and its children from live tree
626+
*
627+
* @np: Node to detach from live tree
628+
*/
629+
static void detach_node_and_children(struct device_node *np)
630+
{
631+
while (np->child)
632+
detach_node_and_children(np->child);
633+
634+
while (np->sibling)
635+
detach_node_and_children(np->sibling);
636+
637+
of_detach_node(np);
638+
}
639+
640+
/**
641+
* selftest_data_remove - removes the selftest data
642+
* nodes from the live tree
643+
*/
644+
static void selftest_data_remove(void)
645+
{
646+
struct device_node *np;
647+
struct property *prop;
648+
649+
while (last_node_index >= 0) {
650+
if (nodes[last_node_index]) {
651+
np = of_find_node_by_path(nodes[last_node_index]->full_name);
652+
if (strcmp(np->full_name, "/aliases") != 0) {
653+
detach_node_and_children(np->child);
654+
of_detach_node(np);
655+
} else {
656+
for_each_property_of_node(np, prop) {
657+
if (strcmp(prop->name, "testcase-alias") == 0)
658+
of_remove_property(np, prop);
659+
}
660+
}
661+
}
662+
last_node_index--;
663+
}
664+
}
665+
520666
static int __init of_selftest(void)
521667
{
522668
struct device_node *np;
669+
int res;
670+
671+
/* adding data for selftest */
672+
res = selftest_data_add();
673+
if (res)
674+
return res;
523675

524676
np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
525677
if (!np) {
@@ -539,6 +691,10 @@ static int __init of_selftest(void)
539691
of_selftest_platform_populate();
540692
pr_info("end of selftest - %i passed, %i failed\n",
541693
selftest_results.passed, selftest_results.failed);
694+
695+
/* removing selftest data from live tree */
696+
selftest_data_remove();
697+
542698
return 0;
543699
}
544700
late_initcall(of_selftest);

drivers/of/testcase-data/testcases.dtsi renamed to drivers/of/testcase-data/testcases.dts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/dts-v1/;
12
#include "tests-phandle.dtsi"
23
#include "tests-interrupts.dtsi"
34
#include "tests-match.dtsi"

0 commit comments

Comments
 (0)