forked from mirrors/linux
		
	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/setup.h>  /* for COMMAND_LINE_SIZE */
 | 
				
			||||||
#include <asm/page.h>
 | 
					#include <asm/page.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "of_private.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * of_fdt_limit_memory - limit the number of regions in the /memory node
 | 
					 * of_fdt_limit_memory - limit the number of regions in the /memory node
 | 
				
			||||||
 * @limit: maximum entries
 | 
					 * @limit: maximum entries
 | 
				
			||||||
| 
						 | 
					@ -469,7 +471,7 @@ static int unflatten_dt_nodes(const void *blob,
 | 
				
			||||||
 * Returns NULL on failure or the memory chunk containing the unflattened
 | 
					 * Returns NULL on failure or the memory chunk containing the unflattened
 | 
				
			||||||
 * device tree on success.
 | 
					 * device tree on success.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void *__unflatten_device_tree(const void *blob,
 | 
					void *__unflatten_device_tree(const void *blob,
 | 
				
			||||||
			      struct device_node *dad,
 | 
								      struct device_node *dad,
 | 
				
			||||||
			      struct device_node **mynodes,
 | 
								      struct device_node **mynodes,
 | 
				
			||||||
			      void *(*dt_alloc)(u64 size, u64 align),
 | 
								      void *(*dt_alloc)(u64 size, u64 align),
 | 
				
			||||||
| 
						 | 
					@ -1261,6 +1263,8 @@ void __init unflatten_device_tree(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
 | 
						/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
 | 
				
			||||||
	of_alias_scan(early_init_dt_alloc_memory_arch);
 | 
						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 */
 | 
					#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.
 | 
					 * General utilities for working with live trees.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,18 @@
 | 
				
			||||||
obj-y += testcases.dtb.o
 | 
					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 += 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: \
 | 
					.PRECIOUS: \
 | 
				
			||||||
	$(obj)/testcases.dtb.S \
 | 
						$(obj)/%.dtb.S \
 | 
				
			||||||
	$(obj)/testcases.dtb
 | 
						$(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/err.h>
 | 
				
			||||||
#include <linux/errno.h>
 | 
					#include <linux/errno.h>
 | 
				
			||||||
#include <linux/hashtable.h>
 | 
					#include <linux/hashtable.h>
 | 
				
			||||||
 | 
					#include <linux/libfdt.h>
 | 
				
			||||||
#include <linux/of.h>
 | 
					#include <linux/of.h>
 | 
				
			||||||
#include <linux/of_fdt.h>
 | 
					#include <linux/of_fdt.h>
 | 
				
			||||||
#include <linux/of_irq.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) { }
 | 
					static inline void __init of_unittest_overlay(void) { }
 | 
				
			||||||
#endif
 | 
					#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)
 | 
					static int __init of_unittest(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct device_node *np;
 | 
						struct device_node *np;
 | 
				
			||||||
| 
						 | 
					@ -1962,6 +2277,8 @@ static int __init of_unittest(void)
 | 
				
			||||||
	/* Double check linkage after removing testcase data */
 | 
						/* Double check linkage after removing testcase data */
 | 
				
			||||||
	of_unittest_check_tree_linkage();
 | 
						of_unittest_check_tree_linkage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						of_unittest_overlay_high_level();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr_info("end of unittest - %i passed, %i failed\n",
 | 
						pr_info("end of unittest - %i passed, %i failed\n",
 | 
				
			||||||
		unittest_results.passed, unittest_results.failed);
 | 
							unittest_results.passed, unittest_results.failed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue