9
9
#include <linux/errno.h>
10
10
#include <linux/module.h>
11
11
#include <linux/of.h>
12
+ #include <linux/of_fdt.h>
12
13
#include <linux/of_irq.h>
13
14
#include <linux/of_platform.h>
14
15
#include <linux/list.h>
@@ -21,6 +22,10 @@ static struct selftest_results {
21
22
int failed ;
22
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
29
#define selftest (result , fmt , ...) { \
25
30
if (!(result)) { \
26
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
666
static int __init of_selftest (void )
521
667
{
522
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
676
np = of_find_node_by_path ("/testcase-data/phandle-tests/consumer-a" );
525
677
if (!np ) {
@@ -539,6 +691,10 @@ static int __init of_selftest(void)
539
691
of_selftest_platform_populate ();
540
692
pr_info ("end of selftest - %i passed, %i failed\n" ,
541
693
selftest_results .passed , selftest_results .failed );
694
+
695
+ /* removing selftest data from live tree */
696
+ selftest_data_remove ();
697
+
542
698
return 0 ;
543
699
}
544
700
late_initcall (of_selftest );
0 commit comments