summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@kernel.org>2024-07-18 14:05:01 -0700
committerStephen Boyd <sboyd@kernel.org>2024-07-29 15:33:12 -0700
commit6774e90f3146818c284b805b16ecdc144dda1c60 (patch)
treef41741a8a52b457c681c77f2235d2d90ef1513d7 /drivers
parent814cff595d1ff6079fb4df2fd8ceeb0b6ad2d221 (diff)
of: Add test managed wrappers for of_overlay_apply()/of_node_put()
Add test managed wrappers for of_overlay_apply() that automatically removes the overlay when the test is finished. This API is intended for use by KUnit tests that test code which relies on 'struct device_node's and of_*() APIs. KUnit tests will call of_overlay_apply_kunit() to load an overlay that's been built into the kernel image. When the test is complete, the overlay will be removed. This has a few benefits: 1) It keeps the tests hermetic because the overlay is removed when the test is complete. Tests won't even be aware that an overlay was loaded in another test. 2) The overlay code can live right next to the unit test that loads it. The overlay and the unit test can be compiled into one kernel module if desired. 3) We can test different device tree configurations by loading different overlays. The overlays can be written for a specific test, and there can be many of them loaded per-test without needing to jam all possible combinations into one DTB. 4) It also allows KUnit to test device tree dependent code on any architecture, not just UML. This allows KUnit tests to test architecture specific device tree code. There are some potential pitfalls though. Test authors need to be careful to not overwrite properties in the live tree. The easiest way to do this is to add and remove nodes with a 'kunit-' prefix, almost guaranteeing that the same node won't be present in the tree loaded at boot. Suggested-by: Rob Herring <robh@kernel.org> Cc: Rob Herring <robh@kernel.org> Cc: Saravana Kannan <saravanak@google.com> Reviewed-by: Rob Herring (Arm) <robh@kernel.org> Reviewed-by: David Gow <davidgow@google.com> Signed-off-by: Stephen Boyd <sboyd@kernel.org> Link: https://lore.kernel.org/r/20240718210513.3801024-3-sboyd@kernel.org
Diffstat (limited to 'drivers')
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/of_kunit_helpers.c77
2 files changed, 78 insertions, 0 deletions
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 251d33532148..2ae909adde49 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -19,6 +19,7 @@ obj-y += kexec.o
endif
endif
+obj-$(CONFIG_KUNIT) += of_kunit_helpers.o
obj-$(CONFIG_OF_KUNIT_TEST) += of_test.o
obj-$(CONFIG_OF_UNITTEST) += unittest-data/
diff --git a/drivers/of/of_kunit_helpers.c b/drivers/of/of_kunit_helpers.c
new file mode 100644
index 000000000000..287d6c91bb37
--- /dev/null
+++ b/drivers/of/of_kunit_helpers.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test managed DeviceTree APIs
+ */
+
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+
+#include <kunit/of.h>
+#include <kunit/test.h>
+#include <kunit/resource.h>
+
+#if defined(CONFIG_OF_OVERLAY) && defined(CONFIG_OF_EARLY_FLATTREE)
+
+static void of_overlay_fdt_apply_kunit_exit(void *ovcs_id)
+{
+ of_overlay_remove(ovcs_id);
+}
+
+/**
+ * of_overlay_fdt_apply_kunit() - Test managed of_overlay_fdt_apply()
+ * @test: test context
+ * @overlay_fdt: device tree overlay to apply
+ * @overlay_fdt_size: size in bytes of @overlay_fdt
+ * @ovcs_id: identifier of overlay, used to remove the overlay
+ *
+ * Just like of_overlay_fdt_apply(), except the overlay is managed by the test
+ * case and is automatically removed with of_overlay_remove() after the test
+ * case concludes.
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int of_overlay_fdt_apply_kunit(struct kunit *test, void *overlay_fdt,
+ u32 overlay_fdt_size, int *ovcs_id)
+{
+ int ret;
+ int *copy_id;
+
+ copy_id = kunit_kmalloc(test, sizeof(*copy_id), GFP_KERNEL);
+ if (!copy_id)
+ return -ENOMEM;
+
+ ret = of_overlay_fdt_apply(overlay_fdt, overlay_fdt_size,
+ ovcs_id, NULL);
+ if (ret)
+ return ret;
+
+ *copy_id = *ovcs_id;
+
+ return kunit_add_action_or_reset(test, of_overlay_fdt_apply_kunit_exit,
+ copy_id);
+}
+EXPORT_SYMBOL_GPL(of_overlay_fdt_apply_kunit);
+
+#endif
+
+KUNIT_DEFINE_ACTION_WRAPPER(of_node_put_wrapper, of_node_put, struct device_node *);
+
+/**
+ * of_node_put_kunit() - Test managed of_node_put()
+ * @test: test context
+ * @node: node to pass to `of_node_put()`
+ *
+ * Just like of_node_put(), except the node is managed by the test case and is
+ * automatically put with of_node_put() after the test case concludes.
+ */
+void of_node_put_kunit(struct kunit *test, struct device_node *node)
+{
+ if (kunit_add_action(test, of_node_put_wrapper, node)) {
+ KUNIT_FAIL(test,
+ "Can't allocate a kunit resource to put of_node\n");
+ }
+}
+EXPORT_SYMBOL_GPL(of_node_put_kunit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Test managed DeviceTree APIs");