mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	of: Add unit tests for applying overlays
Existing overlay unit tests examine individual pieces of the overlay code. The new tests target the entire process of applying an overlay. Signed-off-by: Frank Rowand <frank.rowand@sony.com> Signed-off-by: Rob Herring <robh@kernel.org>
This commit is contained in:
		
							parent
							
								
									331f741679
								
							
						
					
					
						commit
						81d0848fc8
					
				
					 7 changed files with 505 additions and 8 deletions
				
			
		| 
						 | 
				
			
			@ -31,6 +31,8 @@
 | 
			
		|||
#include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
 | 
			
		||||
#include <asm/page.h>
 | 
			
		||||
 | 
			
		||||
#include "of_private.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * of_fdt_limit_memory - limit the number of regions in the /memory node
 | 
			
		||||
 * @limit: maximum entries
 | 
			
		||||
| 
						 | 
				
			
			@ -469,11 +471,11 @@ static int unflatten_dt_nodes(const void *blob,
 | 
			
		|||
 * Returns NULL on failure or the memory chunk containing the unflattened
 | 
			
		||||
 * device tree on success.
 | 
			
		||||
 */
 | 
			
		||||
static void *__unflatten_device_tree(const void *blob,
 | 
			
		||||
				     struct device_node *dad,
 | 
			
		||||
				     struct device_node **mynodes,
 | 
			
		||||
				     void *(*dt_alloc)(u64 size, u64 align),
 | 
			
		||||
				     bool detached)
 | 
			
		||||
void *__unflatten_device_tree(const void *blob,
 | 
			
		||||
			      struct device_node *dad,
 | 
			
		||||
			      struct device_node **mynodes,
 | 
			
		||||
			      void *(*dt_alloc)(u64 size, u64 align),
 | 
			
		||||
			      bool detached)
 | 
			
		||||
{
 | 
			
		||||
	int size;
 | 
			
		||||
	void *mem;
 | 
			
		||||
| 
						 | 
				
			
			@ -1261,6 +1263,8 @@ void __init unflatten_device_tree(void)
 | 
			
		|||
 | 
			
		||||
	/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
 | 
			
		||||
	of_alias_scan(early_init_dt_alloc_memory_arch);
 | 
			
		||||
 | 
			
		||||
	unittest_unflatten_overlay_base();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,18 @@ static inline int of_property_notify(int action, struct device_node *np,
 | 
			
		|||
}
 | 
			
		||||
#endif /* CONFIG_OF_DYNAMIC */
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_OF_UNITTEST
 | 
			
		||||
extern void __init unittest_unflatten_overlay_base(void);
 | 
			
		||||
#else
 | 
			
		||||
static inline void unittest_unflatten_overlay_base(void) {};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern void *__unflatten_device_tree(const void *blob,
 | 
			
		||||
			      struct device_node *dad,
 | 
			
		||||
			      struct device_node **mynodes,
 | 
			
		||||
			      void *(*dt_alloc)(u64 size, u64 align),
 | 
			
		||||
			      bool detached);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * General utilities for working with live trees.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,18 @@
 | 
			
		|||
obj-y += testcases.dtb.o
 | 
			
		||||
obj-y += overlay.dtb.o
 | 
			
		||||
obj-y += overlay_bad_phandle.dtb.o
 | 
			
		||||
obj-y += overlay_base.dtb.o
 | 
			
		||||
 | 
			
		||||
targets += testcases.dtb testcases.dtb.S
 | 
			
		||||
targets += overlay.dtb overlay.dtb.S
 | 
			
		||||
targets += overlay_bad_phandle.dtb overlay_bad_phandle.dtb.S
 | 
			
		||||
targets += overlay_base.dtb overlay_base.dtb.S
 | 
			
		||||
 | 
			
		||||
.SECONDARY: \
 | 
			
		||||
	$(obj)/testcases.dtb.S \
 | 
			
		||||
	$(obj)/testcases.dtb
 | 
			
		||||
.PRECIOUS: \
 | 
			
		||||
	$(obj)/%.dtb.S \
 | 
			
		||||
	$(obj)/%.dtb
 | 
			
		||||
 | 
			
		||||
# enable creation of __symbols__ node
 | 
			
		||||
DTC_FLAGS_overlay := -@
 | 
			
		||||
DTC_FLAGS_overlay_bad_phandle := -@
 | 
			
		||||
DTC_FLAGS_overlay_base := -@
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										53
									
								
								drivers/of/unittest-data/overlay.dts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								drivers/of/unittest-data/overlay.dts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
/dts-v1/;
 | 
			
		||||
/plugin/;
 | 
			
		||||
 | 
			
		||||
/ {
 | 
			
		||||
 | 
			
		||||
	fragment@0 {
 | 
			
		||||
		target = <&electric_1>;
 | 
			
		||||
 | 
			
		||||
		__overlay__ {
 | 
			
		||||
			status = "ok";
 | 
			
		||||
 | 
			
		||||
			hvac_2: hvac-large-1 {
 | 
			
		||||
				compatible = "ot,hvac-large";
 | 
			
		||||
				heat-range = < 40 75 >;
 | 
			
		||||
				cool-range = < 65 80 >;
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	fragment@1 {
 | 
			
		||||
		target = <&rides_1>;
 | 
			
		||||
 | 
			
		||||
		__overlay__ {
 | 
			
		||||
			#address-cells = <1>;
 | 
			
		||||
			#size-cells = <1>;
 | 
			
		||||
			status = "ok";
 | 
			
		||||
 | 
			
		||||
			ride@200 {
 | 
			
		||||
				compatible = "ot,ferris-wheel";
 | 
			
		||||
				reg = < 0x00000200 0x100 >;
 | 
			
		||||
				hvac-provider = < &hvac_2 >;
 | 
			
		||||
				hvac-thermostat = < 27 32 > ;
 | 
			
		||||
				hvac-zones = < 12 5 >;
 | 
			
		||||
				hvac-zone-names = "operator", "snack-bar";
 | 
			
		||||
				spin-controller = < &spin_ctrl_1 3 >;
 | 
			
		||||
				spin-rph = < 30 >;
 | 
			
		||||
				gondolas = < 16 >;
 | 
			
		||||
				gondola-capacity = < 6 >;
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	fragment@2 {
 | 
			
		||||
		target = <&lights_2>;
 | 
			
		||||
 | 
			
		||||
		__overlay__ {
 | 
			
		||||
			status = "ok";
 | 
			
		||||
			color = "purple", "white", "red", "green";
 | 
			
		||||
			rate = < 3 256 >;
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										20
									
								
								drivers/of/unittest-data/overlay_bad_phandle.dts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								drivers/of/unittest-data/overlay_bad_phandle.dts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
/dts-v1/;
 | 
			
		||||
/plugin/;
 | 
			
		||||
 | 
			
		||||
/ {
 | 
			
		||||
 | 
			
		||||
	fragment@0 {
 | 
			
		||||
		target = <&electric_1>;
 | 
			
		||||
 | 
			
		||||
		__overlay__ {
 | 
			
		||||
 | 
			
		||||
			// This label should cause an error when the overlay
 | 
			
		||||
			// is applied.  There is already a phandle value
 | 
			
		||||
			// in the base tree for motor-1.
 | 
			
		||||
			spin_ctrl_1_conflict: motor-1 {
 | 
			
		||||
				accelerate = < 3 >;
 | 
			
		||||
				decelerate = < 5 >;
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										80
									
								
								drivers/of/unittest-data/overlay_base.dts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								drivers/of/unittest-data/overlay_base.dts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,80 @@
 | 
			
		|||
/dts-v1/;
 | 
			
		||||
/plugin/;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Base device tree that overlays will be applied against.
 | 
			
		||||
 *
 | 
			
		||||
 * Do not add any properties in node "/".
 | 
			
		||||
 * Do not add any nodes other than "/testcase-data-2" in node "/".
 | 
			
		||||
 * Do not add anything that would result in dtc creating node "/__fixups__".
 | 
			
		||||
 * dtc will create nodes "/__symbols__" and "/__local_fixups__".
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/ {
 | 
			
		||||
	testcase-data-2 {
 | 
			
		||||
		#address-cells = <1>;
 | 
			
		||||
		#size-cells = <1>;
 | 
			
		||||
 | 
			
		||||
		electric_1: substation@100 {
 | 
			
		||||
			compatible = "ot,big-volts-control";
 | 
			
		||||
			reg = < 0x00000100 0x100 >;
 | 
			
		||||
			status = "disabled";
 | 
			
		||||
 | 
			
		||||
			hvac_1: hvac-medium-1 {
 | 
			
		||||
				compatible = "ot,hvac-medium";
 | 
			
		||||
				heat-range = < 50 75 >;
 | 
			
		||||
				cool-range = < 60 80 >;
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			spin_ctrl_1: motor-1 {
 | 
			
		||||
				compatible = "ot,ferris-wheel-motor";
 | 
			
		||||
				spin = "clockwise";
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			spin_ctrl_2: motor-8 {
 | 
			
		||||
				compatible = "ot,roller-coaster-motor";
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		rides_1: fairway-1 {
 | 
			
		||||
			#address-cells = <1>;
 | 
			
		||||
			#size-cells = <1>;
 | 
			
		||||
			compatible = "ot,rides";
 | 
			
		||||
			status = "disabled";
 | 
			
		||||
			orientation = < 127 >;
 | 
			
		||||
 | 
			
		||||
			ride@100 {
 | 
			
		||||
				compatible = "ot,roller-coaster";
 | 
			
		||||
				reg = < 0x00000100 0x100 >;
 | 
			
		||||
				hvac-provider = < &hvac_1 >;
 | 
			
		||||
				hvac-thermostat = < 29 > ;
 | 
			
		||||
				hvac-zones = < 14 >;
 | 
			
		||||
				hvac-zone-names = "operator";
 | 
			
		||||
				spin-controller = < &spin_ctrl_2 5 &spin_ctrl_2 7 >;
 | 
			
		||||
				spin-controller-names = "track_1", "track_2";
 | 
			
		||||
				queues = < 2 >;
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		lights_1: lights@30000 {
 | 
			
		||||
			compatible = "ot,work-lights";
 | 
			
		||||
			reg = < 0x00030000 0x1000 >;
 | 
			
		||||
			status = "disabled";
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		lights_2: lights@40000 {
 | 
			
		||||
			compatible = "ot,show-lights";
 | 
			
		||||
			reg = < 0x00040000 0x1000 >;
 | 
			
		||||
			status = "disabled";
 | 
			
		||||
			rate = < 13 138 >;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		retail_1: vending@50000 {
 | 
			
		||||
			reg = < 0x00050000 0x1000 >;
 | 
			
		||||
			compatible = "ot,tickets";
 | 
			
		||||
			status = "disabled";
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +8,7 @@
 | 
			
		|||
#include <linux/err.h>
 | 
			
		||||
#include <linux/errno.h>
 | 
			
		||||
#include <linux/hashtable.h>
 | 
			
		||||
#include <linux/libfdt.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include <linux/of_fdt.h>
 | 
			
		||||
#include <linux/of_irq.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -1925,6 +1926,320 @@ static void __init of_unittest_overlay(void)
 | 
			
		|||
static inline void __init of_unittest_overlay(void) { }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * __dtb_ot_begin[] and __dtb_ot_end[] are created by cmd_dt_S_dtb
 | 
			
		||||
 * in scripts/Makefile.lib
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define OVERLAY_INFO_EXTERN(name) \
 | 
			
		||||
	extern uint8_t __dtb_##name##_begin[]; \
 | 
			
		||||
	extern uint8_t __dtb_##name##_end[]
 | 
			
		||||
 | 
			
		||||
#define OVERLAY_INFO(name, expected) \
 | 
			
		||||
{	.dtb_begin	 = __dtb_##name##_begin, \
 | 
			
		||||
	.dtb_end	 = __dtb_##name##_end, \
 | 
			
		||||
	.expected_result = expected, \
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct overlay_info {
 | 
			
		||||
	uint8_t		   *dtb_begin;
 | 
			
		||||
	uint8_t		   *dtb_end;
 | 
			
		||||
	void		   *data;
 | 
			
		||||
	struct device_node *np_overlay;
 | 
			
		||||
	int		   expected_result;
 | 
			
		||||
	int		   overlay_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
OVERLAY_INFO_EXTERN(overlay_base);
 | 
			
		||||
OVERLAY_INFO_EXTERN(overlay);
 | 
			
		||||
OVERLAY_INFO_EXTERN(overlay_bad_phandle);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_OF_OVERLAY
 | 
			
		||||
 | 
			
		||||
/* order of entries is hard-coded into users of overlays[] */
 | 
			
		||||
static struct overlay_info overlays[] = {
 | 
			
		||||
	OVERLAY_INFO(overlay_base, -9999),
 | 
			
		||||
	OVERLAY_INFO(overlay, 0),
 | 
			
		||||
	OVERLAY_INFO(overlay_bad_phandle, -EINVAL),
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct device_node *overlay_base_root;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Create base device tree for the overlay unittest.
 | 
			
		||||
 *
 | 
			
		||||
 * This is called from very early boot code.
 | 
			
		||||
 *
 | 
			
		||||
 * Do as much as possible the same way as done in __unflatten_device_tree
 | 
			
		||||
 * and other early boot steps for the normal FDT so that the overlay base
 | 
			
		||||
 * unflattened tree will have the same characteristics as the real tree
 | 
			
		||||
 * (such as having memory allocated by the early allocator).  The goal
 | 
			
		||||
 * is to test "the real thing" as much as possible, and test "test setup
 | 
			
		||||
 * code" as little as possible.
 | 
			
		||||
 *
 | 
			
		||||
 * Have to stop before resolving phandles, because that uses kmalloc.
 | 
			
		||||
 */
 | 
			
		||||
void __init unittest_unflatten_overlay_base(void)
 | 
			
		||||
{
 | 
			
		||||
	struct overlay_info *info;
 | 
			
		||||
	u32 data_size;
 | 
			
		||||
	u32 size;
 | 
			
		||||
 | 
			
		||||
	info = &overlays[0];
 | 
			
		||||
 | 
			
		||||
	if (info->expected_result != -9999) {
 | 
			
		||||
		pr_err("No dtb 'overlay_base' to attach\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data_size = info->dtb_end - info->dtb_begin;
 | 
			
		||||
	if (!data_size) {
 | 
			
		||||
		pr_err("No dtb 'overlay_base' to attach\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size = fdt_totalsize(info->dtb_begin);
 | 
			
		||||
	if (size != data_size) {
 | 
			
		||||
		pr_err("dtb 'overlay_base' header totalsize != actual size");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info->data = early_init_dt_alloc_memory_arch(size,
 | 
			
		||||
					     roundup_pow_of_two(FDT_V17_SIZE));
 | 
			
		||||
	if (!info->data) {
 | 
			
		||||
		pr_err("alloc for dtb 'overlay_base' failed");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(info->data, info->dtb_begin, size);
 | 
			
		||||
 | 
			
		||||
	__unflatten_device_tree(info->data, NULL, &info->np_overlay,
 | 
			
		||||
				early_init_dt_alloc_memory_arch, true);
 | 
			
		||||
	overlay_base_root = info->np_overlay;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The purpose of of_unittest_overlay_data_add is to add an
 | 
			
		||||
 * overlay in the normal fashion.  This is a test of the whole
 | 
			
		||||
 * picture, instead of testing individual elements.
 | 
			
		||||
 *
 | 
			
		||||
 * A secondary purpose is to be able to verify that the contents of
 | 
			
		||||
 * /proc/device-tree/ contains the updated structure and values from
 | 
			
		||||
 * the overlay.  That must be verified separately in user space.
 | 
			
		||||
 *
 | 
			
		||||
 * Return 0 on unexpected error.
 | 
			
		||||
 */
 | 
			
		||||
static int __init overlay_data_add(int onum)
 | 
			
		||||
{
 | 
			
		||||
	struct overlay_info *info;
 | 
			
		||||
	int k;
 | 
			
		||||
	int ret;
 | 
			
		||||
	u32 size;
 | 
			
		||||
	u32 size_from_header;
 | 
			
		||||
 | 
			
		||||
	for (k = 0, info = overlays; info; info++, k++) {
 | 
			
		||||
		if (k == onum)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	if (onum > k)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	size = info->dtb_end - info->dtb_begin;
 | 
			
		||||
	if (!size) {
 | 
			
		||||
		pr_err("no overlay to attach, %d\n", onum);
 | 
			
		||||
		ret = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_from_header = fdt_totalsize(info->dtb_begin);
 | 
			
		||||
	if (size_from_header != size) {
 | 
			
		||||
		pr_err("overlay header totalsize != actual size, %d", onum);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Must create permanent copy of FDT because of_fdt_unflatten_tree()
 | 
			
		||||
	 * will create pointers to the passed in FDT in the EDT.
 | 
			
		||||
	 */
 | 
			
		||||
	info->data = kmemdup(info->dtb_begin, size, GFP_KERNEL);
 | 
			
		||||
	if (!info->data) {
 | 
			
		||||
		pr_err("unable to allocate memory for data, %d\n", onum);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	of_fdt_unflatten_tree(info->data, NULL, &info->np_overlay);
 | 
			
		||||
	if (!info->np_overlay) {
 | 
			
		||||
		pr_err("unable to unflatten overlay, %d\n", onum);
 | 
			
		||||
		ret = 0;
 | 
			
		||||
		goto out_free_data;
 | 
			
		||||
	}
 | 
			
		||||
	of_node_set_flag(info->np_overlay, OF_DETACHED);
 | 
			
		||||
 | 
			
		||||
	ret = of_resolve_phandles(info->np_overlay);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		pr_err("resolve ot phandles (ret=%d), %d\n", ret, onum);
 | 
			
		||||
		goto out_free_np_overlay;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = of_overlay_create(info->np_overlay);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		pr_err("of_overlay_create() (ret=%d), %d\n", ret, onum);
 | 
			
		||||
		goto out_free_np_overlay;
 | 
			
		||||
	} else {
 | 
			
		||||
		info->overlay_id = ret;
 | 
			
		||||
		ret = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pr_debug("__dtb_overlay_begin applied, overlay id %d\n", ret);
 | 
			
		||||
 | 
			
		||||
	goto out;
 | 
			
		||||
 | 
			
		||||
out_free_np_overlay:
 | 
			
		||||
	/*
 | 
			
		||||
	 * info->np_overlay is the unflattened device tree
 | 
			
		||||
	 * It has not been spliced into the live tree.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* todo: function to free unflattened device tree */
 | 
			
		||||
 | 
			
		||||
out_free_data:
 | 
			
		||||
	kfree(info->data);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return (ret == info->expected_result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The purpose of of_unittest_overlay_high_level is to add an overlay
 | 
			
		||||
 * in the normal fashion.  This is a test of the whole picture,
 | 
			
		||||
 * instead of individual elements.
 | 
			
		||||
 *
 | 
			
		||||
 * The first part of the function is _not_ normal overlay usage; it is
 | 
			
		||||
 * finishing splicing the base overlay device tree into the live tree.
 | 
			
		||||
 */
 | 
			
		||||
static __init void of_unittest_overlay_high_level(void)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *last_sibling;
 | 
			
		||||
	struct device_node *np;
 | 
			
		||||
	struct device_node *of_symbols;
 | 
			
		||||
	struct device_node *overlay_base_symbols;
 | 
			
		||||
	struct device_node **pprev;
 | 
			
		||||
	struct property *prop;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!overlay_base_root) {
 | 
			
		||||
		unittest(0, "overlay_base_root not initialized\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Could not fixup phandles in unittest_unflatten_overlay_base()
 | 
			
		||||
	 * because kmalloc() was not yet available.
 | 
			
		||||
	 */
 | 
			
		||||
	of_resolve_phandles(overlay_base_root);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * do not allow overlay_base to duplicate any node already in
 | 
			
		||||
	 * tree, this greatly simplifies the code
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * remove overlay_base_root node "__local_fixups", after
 | 
			
		||||
	 * being used by of_resolve_phandles()
 | 
			
		||||
	 */
 | 
			
		||||
	pprev = &overlay_base_root->child;
 | 
			
		||||
	for (np = overlay_base_root->child; np; np = np->sibling) {
 | 
			
		||||
		if (!of_node_cmp(np->name, "__local_fixups__")) {
 | 
			
		||||
			*pprev = np->sibling;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		pprev = &np->sibling;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* remove overlay_base_root node "__symbols__" if in live tree */
 | 
			
		||||
	of_symbols = of_get_child_by_name(of_root, "__symbols__");
 | 
			
		||||
	if (of_symbols) {
 | 
			
		||||
		/* will have to graft properties from node into live tree */
 | 
			
		||||
		pprev = &overlay_base_root->child;
 | 
			
		||||
		for (np = overlay_base_root->child; np; np = np->sibling) {
 | 
			
		||||
			if (!of_node_cmp(np->name, "__symbols__")) {
 | 
			
		||||
				overlay_base_symbols = np;
 | 
			
		||||
				*pprev = np->sibling;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			pprev = &np->sibling;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (np = overlay_base_root->child; np; np = np->sibling) {
 | 
			
		||||
		if (of_get_child_by_name(of_root, np->name)) {
 | 
			
		||||
			unittest(0, "illegal node name in overlay_base %s",
 | 
			
		||||
				np->name);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * overlay 'overlay_base' is not allowed to have root
 | 
			
		||||
	 * properties, so only need to splice nodes into main device tree.
 | 
			
		||||
	 *
 | 
			
		||||
	 * root node of *overlay_base_root will not be freed, it is lost
 | 
			
		||||
	 * memory.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	for (np = overlay_base_root->child; np; np = np->sibling)
 | 
			
		||||
		np->parent = of_root;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&of_mutex);
 | 
			
		||||
 | 
			
		||||
	for (np = of_root->child; np; np = np->sibling)
 | 
			
		||||
		last_sibling = np;
 | 
			
		||||
 | 
			
		||||
	if (last_sibling)
 | 
			
		||||
		last_sibling->sibling = overlay_base_root->child;
 | 
			
		||||
	else
 | 
			
		||||
		of_root->child = overlay_base_root->child;
 | 
			
		||||
 | 
			
		||||
	for_each_of_allnodes_from(overlay_base_root, np)
 | 
			
		||||
		__of_attach_node_sysfs(np);
 | 
			
		||||
 | 
			
		||||
	if (of_symbols) {
 | 
			
		||||
		for_each_property_of_node(overlay_base_symbols, prop) {
 | 
			
		||||
			ret = __of_add_property(of_symbols, prop);
 | 
			
		||||
			if (ret) {
 | 
			
		||||
				unittest(0,
 | 
			
		||||
					 "duplicate property '%s' in overlay_base node __symbols__",
 | 
			
		||||
					 prop->name);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			ret = __of_add_property_sysfs(of_symbols, prop);
 | 
			
		||||
			if (ret) {
 | 
			
		||||
				unittest(0,
 | 
			
		||||
					 "unable to add property '%s' in overlay_base node __symbols__ to sysfs",
 | 
			
		||||
					 prop->name);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&of_mutex);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* now do the normal overlay usage test */
 | 
			
		||||
 | 
			
		||||
	unittest(overlay_data_add(1),
 | 
			
		||||
		 "Adding overlay 'overlay' failed\n");
 | 
			
		||||
 | 
			
		||||
	unittest(overlay_data_add(2),
 | 
			
		||||
		 "Adding overlay 'overlay_bad_phandle' failed\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
static inline __init void of_unittest_overlay_high_level(void) {}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int __init of_unittest(void)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *np;
 | 
			
		||||
| 
						 | 
				
			
			@ -1962,6 +2277,8 @@ static int __init of_unittest(void)
 | 
			
		|||
	/* Double check linkage after removing testcase data */
 | 
			
		||||
	of_unittest_check_tree_linkage();
 | 
			
		||||
 | 
			
		||||
	of_unittest_overlay_high_level();
 | 
			
		||||
 | 
			
		||||
	pr_info("end of unittest - %i passed, %i failed\n",
 | 
			
		||||
		unittest_results.passed, unittest_results.failed);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue