mirror of
				https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
				synced 2025-11-04 08:34:47 +10:00 
			
		
		
		
	of/overlay: Add overlay unittests
Add unittests for OF overlays. It tests overlay device addition/removal and whether the apply revert sequence is correct. Changes since V1: * Added local fixups entries. Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> Signed-off-by: Grant Likely <grant.likely@linaro.org>
This commit is contained in:
		
							parent
							
								
									7518b5890d
								
							
						
					
					
						commit
						177d271cf3
					
				
							
								
								
									
										14
									
								
								Documentation/devicetree/bindings/unittest.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Documentation/devicetree/bindings/unittest.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
* OF selftest platform device
 | 
			
		||||
 | 
			
		||||
** selftest
 | 
			
		||||
 | 
			
		||||
Required properties:
 | 
			
		||||
- compatible: must be "selftest"
 | 
			
		||||
 | 
			
		||||
All other properties are optional.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
	selftest {
 | 
			
		||||
		compatible = "selftest";
 | 
			
		||||
		status = "okay";
 | 
			
		||||
	};
 | 
			
		||||
@ -13,6 +13,7 @@
 | 
			
		||||
#include "tests-interrupts.dtsi"
 | 
			
		||||
#include "tests-match.dtsi"
 | 
			
		||||
#include "tests-platform.dtsi"
 | 
			
		||||
#include "tests-overlay.dtsi"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * phandle fixup data - generated by dtc patches that aren't upstream.
 | 
			
		||||
@ -59,5 +60,20 @@
 | 
			
		||||
		testcase-device2 {
 | 
			
		||||
			interrupt-parent = <0x00000000>;
 | 
			
		||||
		};
 | 
			
		||||
		overlay2 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target = <0x00000000>;
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
		overlay3 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target = <0x00000000>;
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
		overlay4 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target = <0x00000000>;
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
}; };
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										180
									
								
								drivers/of/unittest-data/tests-overlay.dtsi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								drivers/of/unittest-data/tests-overlay.dtsi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,180 @@
 | 
			
		||||
 | 
			
		||||
/ {
 | 
			
		||||
	testcase-data {
 | 
			
		||||
		overlay-node {
 | 
			
		||||
 | 
			
		||||
			/* test bus */
 | 
			
		||||
			selftestbus: test-bus {
 | 
			
		||||
				compatible = "simple-bus";
 | 
			
		||||
				#address-cells = <1>;
 | 
			
		||||
				#size-cells = <0>;
 | 
			
		||||
 | 
			
		||||
				selftest100: test-selftest100 {
 | 
			
		||||
					compatible = "selftest";
 | 
			
		||||
					status = "okay";
 | 
			
		||||
					reg = <100>;
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				selftest101: test-selftest101 {
 | 
			
		||||
					compatible = "selftest";
 | 
			
		||||
					status = "disabled";
 | 
			
		||||
					reg = <101>;
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				selftest0: test-selftest0 {
 | 
			
		||||
					compatible = "selftest";
 | 
			
		||||
					status = "disabled";
 | 
			
		||||
					reg = <0>;
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				selftest1: test-selftest1 {
 | 
			
		||||
					compatible = "selftest";
 | 
			
		||||
					status = "okay";
 | 
			
		||||
					reg = <1>;
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				selftest2: test-selftest2 {
 | 
			
		||||
					compatible = "selftest";
 | 
			
		||||
					status = "disabled";
 | 
			
		||||
					reg = <2>;
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				selftest3: test-selftest3 {
 | 
			
		||||
					compatible = "selftest";
 | 
			
		||||
					status = "okay";
 | 
			
		||||
					reg = <3>;
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				selftest5: test-selftest5 {
 | 
			
		||||
					compatible = "selftest";
 | 
			
		||||
					status = "disabled";
 | 
			
		||||
					reg = <5>;
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				selftest6: test-selftest6 {
 | 
			
		||||
					compatible = "selftest";
 | 
			
		||||
					status = "disabled";
 | 
			
		||||
					reg = <6>;
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				selftest7: test-selftest7 {
 | 
			
		||||
					compatible = "selftest";
 | 
			
		||||
					status = "disabled";
 | 
			
		||||
					reg = <7>;
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				selftest8: test-selftest8 {
 | 
			
		||||
					compatible = "selftest";
 | 
			
		||||
					status = "disabled";
 | 
			
		||||
					reg = <8>;
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/* test enable using absolute target path */
 | 
			
		||||
		overlay0 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target-path = "/testcase-data/overlay-node/test-bus/test-selftest0";
 | 
			
		||||
				__overlay__ {
 | 
			
		||||
					status = "okay";
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/* test disable using absolute target path */
 | 
			
		||||
		overlay1 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target-path = "/testcase-data/overlay-node/test-bus/test-selftest1";
 | 
			
		||||
				__overlay__ {
 | 
			
		||||
					status = "disabled";
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/* test enable using label */
 | 
			
		||||
		overlay2 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target = <&selftest2>;
 | 
			
		||||
				__overlay__ {
 | 
			
		||||
					status = "okay";
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/* test disable using label */
 | 
			
		||||
		overlay3 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target = <&selftest3>;
 | 
			
		||||
				__overlay__ {
 | 
			
		||||
					status = "disabled";
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/* test insertion of a full node */
 | 
			
		||||
		overlay4 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target = <&selftestbus>;
 | 
			
		||||
				__overlay__ {
 | 
			
		||||
 | 
			
		||||
					/* suppress DTC warning */
 | 
			
		||||
					#address-cells = <1>;
 | 
			
		||||
					#size-cells = <0>;
 | 
			
		||||
 | 
			
		||||
					test-selftest4 {
 | 
			
		||||
						compatible = "selftest";
 | 
			
		||||
						status = "okay";
 | 
			
		||||
						reg = <4>;
 | 
			
		||||
					};
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/* test overlay apply revert */
 | 
			
		||||
		overlay5 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target-path = "/testcase-data/overlay-node/test-bus/test-selftest5";
 | 
			
		||||
				__overlay__ {
 | 
			
		||||
					status = "okay";
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/* test overlays application and removal in sequence */
 | 
			
		||||
		overlay6 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target-path = "/testcase-data/overlay-node/test-bus/test-selftest6";
 | 
			
		||||
				__overlay__ {
 | 
			
		||||
					status = "okay";
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
		overlay7 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target-path = "/testcase-data/overlay-node/test-bus/test-selftest7";
 | 
			
		||||
				__overlay__ {
 | 
			
		||||
					status = "okay";
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/* test overlays application and removal in bad sequence */
 | 
			
		||||
		overlay8 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target-path = "/testcase-data/overlay-node/test-bus/test-selftest8";
 | 
			
		||||
				__overlay__ {
 | 
			
		||||
					status = "okay";
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
		overlay9 {
 | 
			
		||||
			fragment@0 {
 | 
			
		||||
				target-path = "/testcase-data/overlay-node/test-bus/test-selftest8";
 | 
			
		||||
				__overlay__ {
 | 
			
		||||
					property-foo = "bar";
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
@ -17,6 +17,8 @@
 | 
			
		||||
#include <linux/mutex.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/device.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/of_platform.h>
 | 
			
		||||
 | 
			
		||||
#include "of_private.h"
 | 
			
		||||
 | 
			
		||||
@ -933,6 +935,484 @@ static void selftest_data_remove(void)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_OF_OVERLAY
 | 
			
		||||
 | 
			
		||||
static int selftest_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = &pdev->dev;
 | 
			
		||||
	struct device_node *np = dev->of_node;
 | 
			
		||||
 | 
			
		||||
	if (np == NULL) {
 | 
			
		||||
		dev_err(dev, "No OF data for device\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int selftest_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = &pdev->dev;
 | 
			
		||||
	struct device_node *np = dev->of_node;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct of_device_id selftest_match[] = {
 | 
			
		||||
	{ .compatible = "selftest", },
 | 
			
		||||
	{},
 | 
			
		||||
};
 | 
			
		||||
MODULE_DEVICE_TABLE(of, altera_jtaguart_match);
 | 
			
		||||
 | 
			
		||||
static struct platform_driver selftest_driver = {
 | 
			
		||||
	.probe			= selftest_probe,
 | 
			
		||||
	.remove			= selftest_remove,
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name		= "selftest",
 | 
			
		||||
		.owner		= THIS_MODULE,
 | 
			
		||||
		.of_match_table	= of_match_ptr(selftest_match),
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* get the platform device instantiated at the path */
 | 
			
		||||
static struct platform_device *of_path_to_platform_device(const char *path)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *np;
 | 
			
		||||
	struct platform_device *pdev;
 | 
			
		||||
 | 
			
		||||
	np = of_find_node_by_path(path);
 | 
			
		||||
	if (np == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	pdev = of_find_device_by_node(np);
 | 
			
		||||
	of_node_put(np);
 | 
			
		||||
 | 
			
		||||
	return pdev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* find out if a platform device exists at that path */
 | 
			
		||||
static int of_path_platform_device_exists(const char *path)
 | 
			
		||||
{
 | 
			
		||||
	struct platform_device *pdev;
 | 
			
		||||
 | 
			
		||||
	pdev = of_path_to_platform_device(path);
 | 
			
		||||
	platform_device_put(pdev);
 | 
			
		||||
	return pdev != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *selftest_path(int nr)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[256];
 | 
			
		||||
 | 
			
		||||
	snprintf(buf, sizeof(buf) - 1,
 | 
			
		||||
		"/testcase-data/overlay-node/test-bus/test-selftest%d", nr);
 | 
			
		||||
	buf[sizeof(buf) - 1] = '\0';
 | 
			
		||||
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *overlay_path(int nr)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[256];
 | 
			
		||||
 | 
			
		||||
	snprintf(buf, sizeof(buf) - 1,
 | 
			
		||||
		"/testcase-data/overlay%d", nr);
 | 
			
		||||
	buf[sizeof(buf) - 1] = '\0';
 | 
			
		||||
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *bus_path = "/testcase-data/overlay-node/test-bus";
 | 
			
		||||
 | 
			
		||||
static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
 | 
			
		||||
		int *overlay_id)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *np = NULL;
 | 
			
		||||
	int ret, id = -1;
 | 
			
		||||
 | 
			
		||||
	np = of_find_node_by_path(overlay_path(overlay_nr));
 | 
			
		||||
	if (np == NULL) {
 | 
			
		||||
		selftest(0, "could not find overlay node @\"%s\"\n",
 | 
			
		||||
				overlay_path(overlay_nr));
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = of_overlay_create(np);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		selftest(0, "could not create overlay from \"%s\"\n",
 | 
			
		||||
				overlay_path(overlay_nr));
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	id = ret;
 | 
			
		||||
 | 
			
		||||
	ret = 0;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	of_node_put(np);
 | 
			
		||||
 | 
			
		||||
	if (overlay_id)
 | 
			
		||||
		*overlay_id = id;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* apply an overlay while checking before and after states */
 | 
			
		||||
static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr,
 | 
			
		||||
		int before, int after)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* selftest device must not be in before state */
 | 
			
		||||
	if (of_path_platform_device_exists(selftest_path(selftest_nr))
 | 
			
		||||
			!= before) {
 | 
			
		||||
		selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
 | 
			
		||||
				overlay_path(overlay_nr),
 | 
			
		||||
				selftest_path(selftest_nr),
 | 
			
		||||
				!before ? "enabled" : "disabled");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, NULL);
 | 
			
		||||
	if (ret != 0) {
 | 
			
		||||
		/* of_selftest_apply_overlay already called selftest() */
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* selftest device must be to set to after state */
 | 
			
		||||
	if (of_path_platform_device_exists(selftest_path(selftest_nr))
 | 
			
		||||
			!= after) {
 | 
			
		||||
		selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
 | 
			
		||||
				overlay_path(overlay_nr),
 | 
			
		||||
				selftest_path(selftest_nr),
 | 
			
		||||
				!after ? "enabled" : "disabled");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* apply an overlay and then revert it while checking before, after states */
 | 
			
		||||
static int of_selftest_apply_revert_overlay_check(int overlay_nr,
 | 
			
		||||
		int selftest_nr, int before, int after)
 | 
			
		||||
{
 | 
			
		||||
	int ret, ov_id;
 | 
			
		||||
 | 
			
		||||
	/* selftest device must be in before state */
 | 
			
		||||
	if (of_path_platform_device_exists(selftest_path(selftest_nr))
 | 
			
		||||
			!= before) {
 | 
			
		||||
		selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
 | 
			
		||||
				overlay_path(overlay_nr),
 | 
			
		||||
				selftest_path(selftest_nr),
 | 
			
		||||
				!before ? "enabled" : "disabled");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* apply the overlay */
 | 
			
		||||
	ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, &ov_id);
 | 
			
		||||
	if (ret != 0) {
 | 
			
		||||
		/* of_selftest_apply_overlay already called selftest() */
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* selftest device must be in after state */
 | 
			
		||||
	if (of_path_platform_device_exists(selftest_path(selftest_nr))
 | 
			
		||||
			!= after) {
 | 
			
		||||
		selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
 | 
			
		||||
				overlay_path(overlay_nr),
 | 
			
		||||
				selftest_path(selftest_nr),
 | 
			
		||||
				!after ? "enabled" : "disabled");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = of_overlay_destroy(ov_id);
 | 
			
		||||
	if (ret != 0) {
 | 
			
		||||
		selftest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n",
 | 
			
		||||
				overlay_path(overlay_nr),
 | 
			
		||||
				selftest_path(selftest_nr));
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* selftest device must be again in before state */
 | 
			
		||||
	if (of_path_platform_device_exists(selftest_path(selftest_nr))
 | 
			
		||||
			!= before) {
 | 
			
		||||
		selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
 | 
			
		||||
				overlay_path(overlay_nr),
 | 
			
		||||
				selftest_path(selftest_nr),
 | 
			
		||||
				!before ? "enabled" : "disabled");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* test activation of device */
 | 
			
		||||
static void of_selftest_overlay_0(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* device should enable */
 | 
			
		||||
	ret = of_selftest_apply_overlay_check(0, 0, 0, 1);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	selftest(1, "overlay test %d passed\n", 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* test deactivation of device */
 | 
			
		||||
static void of_selftest_overlay_1(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* device should disable */
 | 
			
		||||
	ret = of_selftest_apply_overlay_check(1, 1, 1, 0);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	selftest(1, "overlay test %d passed\n", 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* test activation of device */
 | 
			
		||||
static void of_selftest_overlay_2(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* device should enable */
 | 
			
		||||
	ret = of_selftest_apply_overlay_check(2, 2, 0, 1);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	selftest(1, "overlay test %d passed\n", 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* test deactivation of device */
 | 
			
		||||
static void of_selftest_overlay_3(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* device should disable */
 | 
			
		||||
	ret = of_selftest_apply_overlay_check(3, 3, 1, 0);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	selftest(1, "overlay test %d passed\n", 3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* test activation of a full device node */
 | 
			
		||||
static void of_selftest_overlay_4(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* device should disable */
 | 
			
		||||
	ret = of_selftest_apply_overlay_check(4, 4, 0, 1);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	selftest(1, "overlay test %d passed\n", 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* test overlay apply/revert sequence */
 | 
			
		||||
static void of_selftest_overlay_5(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* device should disable */
 | 
			
		||||
	ret = of_selftest_apply_revert_overlay_check(5, 5, 0, 1);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	selftest(1, "overlay test %d passed\n", 5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* test overlay application in sequence */
 | 
			
		||||
static void of_selftest_overlay_6(void)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *np;
 | 
			
		||||
	int ret, i, ov_id[2];
 | 
			
		||||
	int overlay_nr = 6, selftest_nr = 6;
 | 
			
		||||
	int before = 0, after = 1;
 | 
			
		||||
 | 
			
		||||
	/* selftest device must be in before state */
 | 
			
		||||
	for (i = 0; i < 2; i++) {
 | 
			
		||||
		if (of_path_platform_device_exists(
 | 
			
		||||
					selftest_path(selftest_nr + i))
 | 
			
		||||
				!= before) {
 | 
			
		||||
			selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
 | 
			
		||||
					overlay_path(overlay_nr + i),
 | 
			
		||||
					selftest_path(selftest_nr + i),
 | 
			
		||||
					!before ? "enabled" : "disabled");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* apply the overlays */
 | 
			
		||||
	for (i = 0; i < 2; i++) {
 | 
			
		||||
 | 
			
		||||
		np = of_find_node_by_path(overlay_path(overlay_nr + i));
 | 
			
		||||
		if (np == NULL) {
 | 
			
		||||
			selftest(0, "could not find overlay node @\"%s\"\n",
 | 
			
		||||
					overlay_path(overlay_nr + i));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ret = of_overlay_create(np);
 | 
			
		||||
		if (ret < 0)  {
 | 
			
		||||
			selftest(0, "could not create overlay from \"%s\"\n",
 | 
			
		||||
					overlay_path(overlay_nr + i));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		ov_id[i] = ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 2; i++) {
 | 
			
		||||
		/* selftest device must be in after state */
 | 
			
		||||
		if (of_path_platform_device_exists(
 | 
			
		||||
					selftest_path(selftest_nr + i))
 | 
			
		||||
				!= after) {
 | 
			
		||||
			selftest(0, "overlay @\"%s\" failed @\"%s\" %s\n",
 | 
			
		||||
					overlay_path(overlay_nr + i),
 | 
			
		||||
					selftest_path(selftest_nr + i),
 | 
			
		||||
					!after ? "enabled" : "disabled");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 1; i >= 0; i--) {
 | 
			
		||||
		ret = of_overlay_destroy(ov_id[i]);
 | 
			
		||||
		if (ret != 0) {
 | 
			
		||||
			selftest(0, "overlay @\"%s\" failed destroy @\"%s\"\n",
 | 
			
		||||
					overlay_path(overlay_nr + i),
 | 
			
		||||
					selftest_path(selftest_nr + i));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 2; i++) {
 | 
			
		||||
		/* selftest device must be again in before state */
 | 
			
		||||
		if (of_path_platform_device_exists(
 | 
			
		||||
					selftest_path(selftest_nr + i))
 | 
			
		||||
				!= before) {
 | 
			
		||||
			selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
 | 
			
		||||
					overlay_path(overlay_nr + i),
 | 
			
		||||
					selftest_path(selftest_nr + i),
 | 
			
		||||
					!before ? "enabled" : "disabled");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	selftest(1, "overlay test %d passed\n", 6);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* test overlay application in sequence */
 | 
			
		||||
static void of_selftest_overlay_8(void)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *np;
 | 
			
		||||
	int ret, i, ov_id[2];
 | 
			
		||||
	int overlay_nr = 8, selftest_nr = 8;
 | 
			
		||||
 | 
			
		||||
	/* we don't care about device state in this test */
 | 
			
		||||
 | 
			
		||||
	/* apply the overlays */
 | 
			
		||||
	for (i = 0; i < 2; i++) {
 | 
			
		||||
 | 
			
		||||
		np = of_find_node_by_path(overlay_path(overlay_nr + i));
 | 
			
		||||
		if (np == NULL) {
 | 
			
		||||
			selftest(0, "could not find overlay node @\"%s\"\n",
 | 
			
		||||
					overlay_path(overlay_nr + i));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ret = of_overlay_create(np);
 | 
			
		||||
		if (ret < 0)  {
 | 
			
		||||
			selftest(0, "could not create overlay from \"%s\"\n",
 | 
			
		||||
					overlay_path(overlay_nr + i));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		ov_id[i] = ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* now try to remove first overlay (it should fail) */
 | 
			
		||||
	ret = of_overlay_destroy(ov_id[0]);
 | 
			
		||||
	if (ret == 0) {
 | 
			
		||||
		selftest(0, "overlay @\"%s\" was destroyed @\"%s\"\n",
 | 
			
		||||
				overlay_path(overlay_nr + 0),
 | 
			
		||||
				selftest_path(selftest_nr));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* removing them in order should work */
 | 
			
		||||
	for (i = 1; i >= 0; i--) {
 | 
			
		||||
		ret = of_overlay_destroy(ov_id[i]);
 | 
			
		||||
		if (ret != 0) {
 | 
			
		||||
			selftest(0, "overlay @\"%s\" not destroyed @\"%s\"\n",
 | 
			
		||||
					overlay_path(overlay_nr + i),
 | 
			
		||||
					selftest_path(selftest_nr));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	selftest(1, "overlay test %d passed\n", 8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __init of_selftest_overlay(void)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *bus_np = NULL;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = platform_driver_register(&selftest_driver);
 | 
			
		||||
	if (ret != 0) {
 | 
			
		||||
		selftest(0, "could not register selftest driver\n");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bus_np = of_find_node_by_path(bus_path);
 | 
			
		||||
	if (bus_np == NULL) {
 | 
			
		||||
		selftest(0, "could not find bus_path \"%s\"\n", bus_path);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = of_platform_populate(bus_np, of_default_bus_match_table,
 | 
			
		||||
			NULL, NULL);
 | 
			
		||||
	if (ret != 0) {
 | 
			
		||||
		selftest(0, "could not populate bus @ \"%s\"\n", bus_path);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!of_path_platform_device_exists(selftest_path(100))) {
 | 
			
		||||
		selftest(0, "could not find selftest0 @ \"%s\"\n",
 | 
			
		||||
				selftest_path(100));
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (of_path_platform_device_exists(selftest_path(101))) {
 | 
			
		||||
		selftest(0, "selftest1 @ \"%s\" should not exist\n",
 | 
			
		||||
				selftest_path(101));
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	selftest(1, "basic infrastructure of overlays passed");
 | 
			
		||||
 | 
			
		||||
	/* tests in sequence */
 | 
			
		||||
	of_selftest_overlay_0();
 | 
			
		||||
	of_selftest_overlay_1();
 | 
			
		||||
	of_selftest_overlay_2();
 | 
			
		||||
	of_selftest_overlay_3();
 | 
			
		||||
	of_selftest_overlay_4();
 | 
			
		||||
	of_selftest_overlay_5();
 | 
			
		||||
	of_selftest_overlay_6();
 | 
			
		||||
	of_selftest_overlay_8();
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	of_node_put(bus_np);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
static inline void __init of_selftest_overlay(void) { }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int __init of_selftest(void)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *np;
 | 
			
		||||
@ -965,6 +1445,7 @@ static int __init of_selftest(void)
 | 
			
		||||
	of_selftest_parse_interrupts_extended();
 | 
			
		||||
	of_selftest_match_node();
 | 
			
		||||
	of_selftest_platform_populate();
 | 
			
		||||
	of_selftest_overlay();
 | 
			
		||||
 | 
			
		||||
	/* removing selftest data from live tree */
 | 
			
		||||
	selftest_data_remove();
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user