forked from mirrors/linux
		
	of: Add device tree selftests
Add some runtime test cases for the library of device tree parsing functions.
v2: - Add testcase for phandle with 0 args
    - Don't run testcases if testcase data isn't present in device tree
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
			
			
This commit is contained in:
		
							parent
							
								
									15c9a0acc3
								
							
						
					
					
						commit
						53a42093d9
					
				
					 6 changed files with 189 additions and 0 deletions
				
			
		
							
								
								
									
										37
									
								
								arch/arm/boot/dts/testcases/tests-phandle.dtsi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								arch/arm/boot/dts/testcases/tests-phandle.dtsi
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/ {
 | 
				
			||||||
 | 
						testcase-data {
 | 
				
			||||||
 | 
							phandle-tests {
 | 
				
			||||||
 | 
								provider0: provider0 {
 | 
				
			||||||
 | 
									#phandle-cells = <0>;
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								provider1: provider1 {
 | 
				
			||||||
 | 
									#phandle-cells = <1>;
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								provider2: provider2 {
 | 
				
			||||||
 | 
									#phandle-cells = <2>;
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								provider3: provider3 {
 | 
				
			||||||
 | 
									#phandle-cells = <3>;
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								consumer-a {
 | 
				
			||||||
 | 
									phandle-list =	<&provider1 1>,
 | 
				
			||||||
 | 
											<&provider2 2 0>,
 | 
				
			||||||
 | 
											<0>,
 | 
				
			||||||
 | 
											<&provider3 4 4 3>,
 | 
				
			||||||
 | 
											<&provider2 5 100>,
 | 
				
			||||||
 | 
											<&provider0>,
 | 
				
			||||||
 | 
											<&provider1 7>;
 | 
				
			||||||
 | 
									phandle-list-names = "first", "second", "third";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									phandle-list-bad-phandle = <12345678 0 0>;
 | 
				
			||||||
 | 
									phandle-list-bad-args = <&provider2 1 0>,
 | 
				
			||||||
 | 
												<&provider3 0>;
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										1
									
								
								arch/arm/boot/dts/testcases/tests.dtsi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								arch/arm/boot/dts/testcases/tests.dtsi
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					/include/ "tests-phandle.dtsi"
 | 
				
			||||||
| 
						 | 
					@ -46,3 +46,5 @@ mmc@b000 {
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/include/ "testcases/tests.dtsi"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,15 @@ config PROC_DEVICETREE
 | 
				
			||||||
	  an image of the device tree that the kernel copies from Open
 | 
						  an image of the device tree that the kernel copies from Open
 | 
				
			||||||
	  Firmware or other boot firmware. If unsure, say Y here.
 | 
						  Firmware or other boot firmware. If unsure, say Y here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config OF_SELFTEST
 | 
				
			||||||
 | 
						bool "Device Tree Runtime self tests"
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  This option builds in test cases for the device tree infrastructure
 | 
				
			||||||
 | 
						  that are executed one at boot time, and the results dumped to the
 | 
				
			||||||
 | 
						  console.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  If unsure, say N here, but this option is safe to enable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config OF_FLATTREE
 | 
					config OF_FLATTREE
 | 
				
			||||||
	bool
 | 
						bool
 | 
				
			||||||
	select DTC
 | 
						select DTC
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ obj-$(CONFIG_OF_GPIO)   += gpio.o
 | 
				
			||||||
obj-$(CONFIG_OF_I2C)	+= of_i2c.o
 | 
					obj-$(CONFIG_OF_I2C)	+= of_i2c.o
 | 
				
			||||||
obj-$(CONFIG_OF_NET)	+= of_net.o
 | 
					obj-$(CONFIG_OF_NET)	+= of_net.o
 | 
				
			||||||
obj-$(CONFIG_OF_SPI)	+= of_spi.o
 | 
					obj-$(CONFIG_OF_SPI)	+= of_spi.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_OF_SELFTEST) += selftest.o
 | 
				
			||||||
obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
 | 
					obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
 | 
				
			||||||
obj-$(CONFIG_OF_PCI)	+= of_pci.o
 | 
					obj-$(CONFIG_OF_PCI)	+= of_pci.o
 | 
				
			||||||
obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
 | 
					obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										139
									
								
								drivers/of/selftest.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								drivers/of/selftest.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,139 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Self tests for device tree subsystem
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define pr_fmt(fmt) "### %s(): " fmt, __func__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/clk.h>
 | 
				
			||||||
 | 
					#include <linux/err.h>
 | 
				
			||||||
 | 
					#include <linux/errno.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/of.h>
 | 
				
			||||||
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/device.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool selftest_passed = true;
 | 
				
			||||||
 | 
					#define selftest(result, fmt, ...) { \
 | 
				
			||||||
 | 
						selftest_passed &= (result); \
 | 
				
			||||||
 | 
						if (!(result)) \
 | 
				
			||||||
 | 
							pr_err("FAIL %s:%i " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __init of_selftest_parse_phandle_with_args(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct device_node *np;
 | 
				
			||||||
 | 
						struct of_phandle_args args;
 | 
				
			||||||
 | 
						int rc, i;
 | 
				
			||||||
 | 
						bool passed_all = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pr_info("start\n");
 | 
				
			||||||
 | 
						np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
 | 
				
			||||||
 | 
						if (!np) {
 | 
				
			||||||
 | 
							pr_err("missing testcase data\n");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < 7; i++) {
 | 
				
			||||||
 | 
							bool passed = true;
 | 
				
			||||||
 | 
							rc = of_parse_phandle_with_args(np, "phandle-list",
 | 
				
			||||||
 | 
											"#phandle-cells", i, &args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Test the values from tests-phandle.dtsi */
 | 
				
			||||||
 | 
							switch (i) {
 | 
				
			||||||
 | 
							case 0:
 | 
				
			||||||
 | 
								passed &= !rc;
 | 
				
			||||||
 | 
								passed &= (args.args_count == 1);
 | 
				
			||||||
 | 
								passed &= (args.args[0] == (i + 1));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 1:
 | 
				
			||||||
 | 
								passed &= !rc;
 | 
				
			||||||
 | 
								passed &= (args.args_count == 2);
 | 
				
			||||||
 | 
								passed &= (args.args[0] == (i + 1));
 | 
				
			||||||
 | 
								passed &= (args.args[1] == 0);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 2:
 | 
				
			||||||
 | 
								passed &= (rc == -ENOENT);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 3:
 | 
				
			||||||
 | 
								passed &= !rc;
 | 
				
			||||||
 | 
								passed &= (args.args_count == 3);
 | 
				
			||||||
 | 
								passed &= (args.args[0] == (i + 1));
 | 
				
			||||||
 | 
								passed &= (args.args[1] == 4);
 | 
				
			||||||
 | 
								passed &= (args.args[2] == 3);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 4:
 | 
				
			||||||
 | 
								passed &= !rc;
 | 
				
			||||||
 | 
								passed &= (args.args_count == 2);
 | 
				
			||||||
 | 
								passed &= (args.args[0] == (i + 1));
 | 
				
			||||||
 | 
								passed &= (args.args[1] == 100);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 5:
 | 
				
			||||||
 | 
								passed &= !rc;
 | 
				
			||||||
 | 
								passed &= (args.args_count == 0);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 6:
 | 
				
			||||||
 | 
								passed &= !rc;
 | 
				
			||||||
 | 
								passed &= (args.args_count == 1);
 | 
				
			||||||
 | 
								passed &= (args.args[0] == (i + 1));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 7:
 | 
				
			||||||
 | 
								passed &= (rc == -EINVAL);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								passed = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!passed) {
 | 
				
			||||||
 | 
								int j;
 | 
				
			||||||
 | 
								pr_err("index %i - data error on node %s rc=%i regs=[",
 | 
				
			||||||
 | 
									i, args.np->full_name, rc);
 | 
				
			||||||
 | 
								for (j = 0; j < args.args_count; j++)
 | 
				
			||||||
 | 
									printk(" %i", args.args[j]);
 | 
				
			||||||
 | 
								printk(" ]\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								passed_all = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check for missing list property */
 | 
				
			||||||
 | 
						rc = of_parse_phandle_with_args(np, "phandle-list-missing",
 | 
				
			||||||
 | 
										"#phandle-cells", 0, &args);
 | 
				
			||||||
 | 
						passed_all &= (rc == -EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check for missing cells property */
 | 
				
			||||||
 | 
						rc = of_parse_phandle_with_args(np, "phandle-list",
 | 
				
			||||||
 | 
										"#phandle-cells-missing", 0, &args);
 | 
				
			||||||
 | 
						passed_all &= (rc == -EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check for bad phandle in list */
 | 
				
			||||||
 | 
						rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle",
 | 
				
			||||||
 | 
										"#phandle-cells", 0, &args);
 | 
				
			||||||
 | 
						passed_all &= (rc == -EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check for incorrectly formed argument list */
 | 
				
			||||||
 | 
						rc = of_parse_phandle_with_args(np, "phandle-list-bad-args",
 | 
				
			||||||
 | 
										"#phandle-cells", 1, &args);
 | 
				
			||||||
 | 
						passed_all &= (rc == -EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pr_info("end - %s\n", passed_all ? "PASS" : "FAIL");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __init of_selftest(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct device_node *np;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
 | 
				
			||||||
 | 
						if (!np) {
 | 
				
			||||||
 | 
							pr_info("No testcase data in device tree; not running tests\n");
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						of_node_put(np);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pr_info("start of selftest - you will see error messages\n");
 | 
				
			||||||
 | 
						of_selftest_parse_phandle_with_args();
 | 
				
			||||||
 | 
						pr_info("end of selftest - %s\n", selftest_passed ? "PASS" : "FAIL");
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					late_initcall(of_selftest);
 | 
				
			||||||
		Loading…
	
		Reference in a new issue