aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/boot/dts/versatile-pb.dts2
-rw-r--r--drivers/of/Kconfig1
-rw-r--r--drivers/of/Makefile3
-rw-r--r--drivers/of/selftest.c156
-rw-r--r--drivers/of/testcase-data/testcases.dts (renamed from drivers/of/testcase-data/testcases.dtsi)1
5 files changed, 160 insertions, 3 deletions
diff --git a/arch/arm/boot/dts/versatile-pb.dts b/arch/arm/boot/dts/versatile-pb.dts
index 65f657711323..8d39677b7d4c 100644
--- a/arch/arm/boot/dts/versatile-pb.dts
+++ b/arch/arm/boot/dts/versatile-pb.dts
@@ -46,5 +46,3 @@
46 }; 46 };
47 }; 47 };
48}; 48};
49
50#include <testcases.dtsi>
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 2dcb0541012d..868f3712bc67 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -10,6 +10,7 @@ menu "Device Tree and Open Firmware support"
10config OF_SELFTEST 10config OF_SELFTEST
11 bool "Device Tree Runtime self tests" 11 bool "Device Tree Runtime self tests"
12 depends on OF_IRQ 12 depends on OF_IRQ
13 select OF_DYNAMIC
13 help 14 help
14 This option builds in test cases for the device tree infrastructure 15 This option builds in test cases for the device tree infrastructure
15 that are executed once at boot time, and the results dumped to the 16 that are executed once at boot time, and the results dumped to the
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 099b1fb00af4..b9e753b56964 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -5,7 +5,8 @@ obj-$(CONFIG_OF_PROMTREE) += pdt.o
5obj-$(CONFIG_OF_ADDRESS) += address.o 5obj-$(CONFIG_OF_ADDRESS) += address.o
6obj-$(CONFIG_OF_IRQ) += irq.o 6obj-$(CONFIG_OF_IRQ) += irq.o
7obj-$(CONFIG_OF_NET) += of_net.o 7obj-$(CONFIG_OF_NET) += of_net.o
8obj-$(CONFIG_OF_SELFTEST) += selftest.o 8obj-$(CONFIG_OF_SELFTEST) += of_selftest.o
9of_selftest-objs := selftest.o testcase-data/testcases.dtb.o
9obj-$(CONFIG_OF_MDIO) += of_mdio.o 10obj-$(CONFIG_OF_MDIO) += of_mdio.o
10obj-$(CONFIG_OF_PCI) += of_pci.o 11obj-$(CONFIG_OF_PCI) += of_pci.o
11obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o 12obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
index 077314eebb95..df599db1554c 100644
--- a/drivers/of/selftest.c
+++ b/drivers/of/selftest.c
@@ -9,6 +9,7 @@
9#include <linux/errno.h> 9#include <linux/errno.h>
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/of.h> 11#include <linux/of.h>
12#include <linux/of_fdt.h>
12#include <linux/of_irq.h> 13#include <linux/of_irq.h>
13#include <linux/of_platform.h> 14#include <linux/of_platform.h>
14#include <linux/list.h> 15#include <linux/list.h>
@@ -21,6 +22,10 @@ static struct selftest_results {
21 int failed; 22 int failed;
22} selftest_results; 23} selftest_results;
23 24
25#define NO_OF_NODES 2
26static struct device_node *nodes[NO_OF_NODES];
27static int last_node_index;
28
24#define selftest(result, fmt, ...) { \ 29#define selftest(result, fmt, ...) { \
25 if (!(result)) { \ 30 if (!(result)) { \
26 selftest_results.failed++; \ 31 selftest_results.failed++; \
@@ -517,9 +522,156 @@ static void __init of_selftest_platform_populate(void)
517 } 522 }
518} 523}
519 524
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 */
533static 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 */
552static 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 */
595static 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 */
629static 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 */
644static 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
520static int __init of_selftest(void) 666static int __init of_selftest(void)
521{ 667{
522 struct device_node *np; 668 struct device_node *np;
669 int res;
670
671 /* adding data for selftest */
672 res = selftest_data_add();
673 if (res)
674 return res;
523 675
524 np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); 676 np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
525 if (!np) { 677 if (!np) {
@@ -539,6 +691,10 @@ static int __init of_selftest(void)
539 of_selftest_platform_populate(); 691 of_selftest_platform_populate();
540 pr_info("end of selftest - %i passed, %i failed\n", 692 pr_info("end of selftest - %i passed, %i failed\n",
541 selftest_results.passed, selftest_results.failed); 693 selftest_results.passed, selftest_results.failed);
694
695 /* removing selftest data from live tree */
696 selftest_data_remove();
697
542 return 0; 698 return 0;
543} 699}
544late_initcall(of_selftest); 700late_initcall(of_selftest);
diff --git a/drivers/of/testcase-data/testcases.dtsi b/drivers/of/testcase-data/testcases.dts
index 6d8d980ac858..8e7568ee3175 100644
--- a/drivers/of/testcase-data/testcases.dtsi
+++ b/drivers/of/testcase-data/testcases.dts
@@ -1,3 +1,4 @@
1/dts-v1/;
1#include "tests-phandle.dtsi" 2#include "tests-phandle.dtsi"
2#include "tests-interrupts.dtsi" 3#include "tests-interrupts.dtsi"
3#include "tests-match.dtsi" 4#include "tests-match.dtsi"