@@ -19,6 +19,8 @@ obj-y += kexec.o
endif
endif
+obj-$(CONFIG_KUNIT) += of_kunit.o
+
DTC_FLAGS_kunit += -@
obj-$(CONFIG_OF_KUNIT) += kunit.dtbo.o
obj-$(CONFIG_OF_KUNIT_TEST) += of_test.o
new file mode 100644
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test managed device tree APIs
+ */
+
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+
+#include <kunit/of.h>
+#include <kunit/test.h>
+#include <kunit/resource.h>
+
+struct of_overlay_fdt_apply_kunit_params {
+ void *overlay_fdt;
+ u32 overlay_fdt_size;
+ int *ovcs_id;
+};
+
+static int of_overlay_fdt_apply_kunit_init(struct kunit_resource *res, void *context)
+{
+ struct of_overlay_fdt_apply_kunit_params *params = context;
+ int ret;
+
+ ret = of_overlay_fdt_apply(params->overlay_fdt, params->overlay_fdt_size, params->ovcs_id);
+ if (ret)
+ return ret;
+
+ res->data = (void *)(uintptr_t)(*params->ovcs_id);
+
+ return 0;
+}
+
+static void of_overlay_fdt_apply_kunit_exit(struct kunit_resource *res)
+{
+ int ovcs_id = (uintptr_t)res->data;
+
+ 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.
+ *
+ * Returns: 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)
+{
+ struct of_overlay_fdt_apply_kunit_params params = {
+ .overlay_fdt = overlay_fdt,
+ .overlay_fdt_size = overlay_fdt_size,
+ .ovcs_id = ovcs_id,
+ };
+
+ if (!IS_ENABLED(CONFIG_OF_OVERLAY))
+ kunit_skip(test, "requires CONFIG_OF_OVERLAY");
+
+ if (!kunit_alloc_resource(test,
+ of_overlay_fdt_apply_kunit_init,
+ of_overlay_fdt_apply_kunit_exit,
+ GFP_KERNEL, ¶ms))
+ return -ENOMEM;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_overlay_fdt_apply_kunit);
+
+/**
+ * __of_overlay_apply_kunit() - Test managed of_overlay_fdt_apply() variant
+ * @test: test context
+ * @overlay_begin: start address of overlay to apply
+ * @overlay_end: end address of overlay to apply
+ *
+ * Similar to `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.
+ *
+ * Returns: 0 on success, negative errno on failure.
+ */
+int __of_overlay_apply_kunit(struct kunit *test, u8 *overlay_begin,
+ const u8 *overlay_end)
+{
+ int unused;
+
+ return of_overlay_fdt_apply_kunit(test, overlay_begin,
+ overlay_end - overlay_begin,
+ &unused);
+}
+EXPORT_SYMBOL_GPL(__of_overlay_apply_kunit);
+
+static void of_node_put_kunit_exit(struct kunit_resource *res)
+{
+ struct device_node *node = res->data;
+
+ of_node_put(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.
+ *
+ * Returns: 0 on success, negative errno on failure.
+ */
+void of_node_put_kunit(struct kunit *test, struct device_node *node)
+{
+ if (!kunit_alloc_resource(test, NULL, of_node_put_kunit_exit,
+ GFP_KERNEL, node))
+ KUNIT_FAIL(test,
+ "Can't allocate a kunit resource to put of_node\n");
+}
+EXPORT_SYMBOL_GPL(of_node_put_kunit);
new file mode 100644
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _KUNIT_OF_H
+#define _KUNIT_OF_H
+
+#include <kunit/test.h>
+
+struct device_node;
+
+#ifdef CONFIG_OF
+
+int of_overlay_fdt_apply_kunit(struct kunit *test, void *overlay_fdt,
+ u32 overlay_fdt_size, int *ovcs_id);
+int __of_overlay_apply_kunit(struct kunit *test, u8 *overlay_begin,
+ const u8 *overlay_end);
+
+void of_node_put_kunit(struct kunit *test, struct device_node *node);
+
+#else
+
+static inline int
+of_overlay_fdt_apply_kunit(struct kunit *test, void *overlay_fdt,
+ u32 overlay_fdt_size, int *ovcs_id)
+{
+ kunit_skip(test, "requires CONFIG_OF");
+ return -EINVAL;
+}
+
+static inline int
+__of_overlay_apply_kunit(struct kunit *test, u8 *overlay_begin,
+ const u8 *overlay_end)
+{
+ kunit_skip(test, "requires CONFIG_OF");
+ return -EINVAL;
+}
+
+static inline
+void of_node_put_kunit(struct kunit *test, struct device_node *node)
+{
+ kunit_skip(test, "requires CONFIG_OF");
+}
+
+#endif /* !CONFIG_OF */
+
+/**
+ * of_overlay_apply_kunit() - Test managed of_overlay_fdt_apply() for built-in overlays
+ * @test: test context
+ * @overlay_name: name of overlay to apply
+ *
+ * This macro is used to apply a device tree overlay built with the
+ * cmd_dt_S_dtbo rule in scripts/Makefile.lib that has been compiled into the
+ * kernel image or KUnit test module. The overlay is automatically removed when
+ * the test is finished.
+ *
+ * Unit tests that need device tree nodes should compile an overlay file with
+ * `@overlay_name`.dtbo.o in their Makefile along with their unit test and then
+ * load the overlay during their test. The @overlay_name matches the filename
+ * of the overlay. If CONFIG_OF_OVERLAY is not enabled, the @test will be
+ * skipped.
+ *
+ * .. code-block:: none
+ *
+ * obj-$(CONFIG_OF_OVERLAY_KUNIT_TEST) += overlay_test.o kunit_overlay_test.dtbo.o
+ *
+ * .. code-block:: c
+ *
+ * static void of_overlay_kunit_of_overlay_apply(struct kunit *test)
+ * {
+ * struct device_node *np;
+ *
+ * KUNIT_ASSERT_EQ(test, 0,
+ * of_overlay_apply_kunit(test, kunit_overlay_test));
+ *
+ * np = of_find_node_by_name(NULL, "test-kunit");
+ * KUNIT_EXPECT_NOT_ERR_OR_NULL(test, np);
+ * of_node_put(np);
+ * }
+ *
+ * Returns: 0 on success, negative errno on failure.
+ */
+#define of_overlay_apply_kunit(test, overlay_name) \
+({ \
+ extern uint8_t __dtbo_##overlay_name##_begin[]; \
+ extern uint8_t __dtbo_##overlay_name##_end[]; \
+ \
+ __of_overlay_apply_kunit((test), \
+ __dtbo_##overlay_name##_begin, \
+ __dtbo_##overlay_name##_end); \
+})
+
+#endif