diff options
-rw-r--r-- | arch/arm/boot/dts/versatile-pb.dts | 2 | ||||
-rw-r--r-- | drivers/of/Kconfig | 1 | ||||
-rw-r--r-- | drivers/of/Makefile | 3 | ||||
-rw-r--r-- | drivers/of/selftest.c | 156 | ||||
-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" | |||
10 | config OF_SELFTEST | 10 | config 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 | |||
5 | obj-$(CONFIG_OF_ADDRESS) += address.o | 5 | obj-$(CONFIG_OF_ADDRESS) += address.o |
6 | obj-$(CONFIG_OF_IRQ) += irq.o | 6 | obj-$(CONFIG_OF_IRQ) += irq.o |
7 | obj-$(CONFIG_OF_NET) += of_net.o | 7 | 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 | ||
9 | obj-$(CONFIG_OF_MDIO) += of_mdio.o | 10 | obj-$(CONFIG_OF_MDIO) += of_mdio.o |
10 | obj-$(CONFIG_OF_PCI) += of_pci.o | 11 | obj-$(CONFIG_OF_PCI) += of_pci.o |
11 | obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o | 12 | obj-$(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 | ||
26 | static struct device_node *nodes[NO_OF_NODES]; | ||
27 | static 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 | */ | ||
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 | |||
520 | static int __init of_selftest(void) | 666 | static 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 | } |
544 | late_initcall(of_selftest); | 700 | late_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" |