Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+217
+11
Documentation/dev-tools/kunit/api/index.rst
··· 9 9 test 10 10 resource 11 11 functionredirection 12 + of 12 13 13 14 14 15 This page documents the KUnit kernel testing API. It is divided into the 15 16 following sections: 17 + 18 + Core KUnit API 19 + ============== 16 20 17 21 Documentation/dev-tools/kunit/api/test.rst 18 22 ··· 29 25 Documentation/dev-tools/kunit/api/functionredirection.rst 30 26 31 27 - Documents the KUnit Function Redirection API 28 + 29 + Driver KUnit API 30 + ================ 31 + 32 + Documentation/dev-tools/kunit/api/of.rst 33 + 34 + - Documents the KUnit device tree (OF) API
+13
Documentation/dev-tools/kunit/api/of.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ==================== 4 + Device Tree (OF) API 5 + ==================== 6 + 7 + The KUnit device tree API is used to test device tree (of_*) dependent code. 8 + 9 + .. kernel-doc:: include/kunit/of.h 10 + :internal: 11 + 12 + .. kernel-doc:: drivers/of/of_kunit_helpers.c 13 + :export:
+1
drivers/of/Makefile
··· 19 19 endif 20 20 endif 21 21 22 + obj-$(CONFIG_KUNIT) += of_kunit_helpers.o 22 23 obj-$(CONFIG_OF_KUNIT_TEST) += of_test.o 23 24 24 25 obj-$(CONFIG_OF_UNITTEST) += unittest-data/
+77
drivers/of/of_kunit_helpers.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Test managed DeviceTree APIs 4 + */ 5 + 6 + #include <linux/of.h> 7 + #include <linux/of_fdt.h> 8 + 9 + #include <kunit/of.h> 10 + #include <kunit/test.h> 11 + #include <kunit/resource.h> 12 + 13 + #if defined(CONFIG_OF_OVERLAY) && defined(CONFIG_OF_EARLY_FLATTREE) 14 + 15 + static void of_overlay_fdt_apply_kunit_exit(void *ovcs_id) 16 + { 17 + of_overlay_remove(ovcs_id); 18 + } 19 + 20 + /** 21 + * of_overlay_fdt_apply_kunit() - Test managed of_overlay_fdt_apply() 22 + * @test: test context 23 + * @overlay_fdt: device tree overlay to apply 24 + * @overlay_fdt_size: size in bytes of @overlay_fdt 25 + * @ovcs_id: identifier of overlay, used to remove the overlay 26 + * 27 + * Just like of_overlay_fdt_apply(), except the overlay is managed by the test 28 + * case and is automatically removed with of_overlay_remove() after the test 29 + * case concludes. 30 + * 31 + * Return: 0 on success, negative errno on failure 32 + */ 33 + int of_overlay_fdt_apply_kunit(struct kunit *test, void *overlay_fdt, 34 + u32 overlay_fdt_size, int *ovcs_id) 35 + { 36 + int ret; 37 + int *copy_id; 38 + 39 + copy_id = kunit_kmalloc(test, sizeof(*copy_id), GFP_KERNEL); 40 + if (!copy_id) 41 + return -ENOMEM; 42 + 43 + ret = of_overlay_fdt_apply(overlay_fdt, overlay_fdt_size, 44 + ovcs_id, NULL); 45 + if (ret) 46 + return ret; 47 + 48 + *copy_id = *ovcs_id; 49 + 50 + return kunit_add_action_or_reset(test, of_overlay_fdt_apply_kunit_exit, 51 + copy_id); 52 + } 53 + EXPORT_SYMBOL_GPL(of_overlay_fdt_apply_kunit); 54 + 55 + #endif 56 + 57 + KUNIT_DEFINE_ACTION_WRAPPER(of_node_put_wrapper, of_node_put, struct device_node *); 58 + 59 + /** 60 + * of_node_put_kunit() - Test managed of_node_put() 61 + * @test: test context 62 + * @node: node to pass to `of_node_put()` 63 + * 64 + * Just like of_node_put(), except the node is managed by the test case and is 65 + * automatically put with of_node_put() after the test case concludes. 66 + */ 67 + void of_node_put_kunit(struct kunit *test, struct device_node *node) 68 + { 69 + if (kunit_add_action(test, of_node_put_wrapper, node)) { 70 + KUNIT_FAIL(test, 71 + "Can't allocate a kunit resource to put of_node\n"); 72 + } 73 + } 74 + EXPORT_SYMBOL_GPL(of_node_put_kunit); 75 + 76 + MODULE_LICENSE("GPL"); 77 + MODULE_DESCRIPTION("Test managed DeviceTree APIs");
+115
include/kunit/of.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _KUNIT_OF_H 3 + #define _KUNIT_OF_H 4 + 5 + #include <kunit/test.h> 6 + 7 + struct device_node; 8 + 9 + #ifdef CONFIG_OF 10 + 11 + void of_node_put_kunit(struct kunit *test, struct device_node *node); 12 + 13 + #else 14 + 15 + static inline 16 + void of_node_put_kunit(struct kunit *test, struct device_node *node) 17 + { 18 + kunit_skip(test, "requires CONFIG_OF"); 19 + } 20 + 21 + #endif /* !CONFIG_OF */ 22 + 23 + #if defined(CONFIG_OF) && defined(CONFIG_OF_OVERLAY) && defined(CONFIG_OF_EARLY_FLATTREE) 24 + 25 + int of_overlay_fdt_apply_kunit(struct kunit *test, void *overlay_fdt, 26 + u32 overlay_fdt_size, int *ovcs_id); 27 + #else 28 + 29 + static inline int 30 + of_overlay_fdt_apply_kunit(struct kunit *test, void *overlay_fdt, 31 + u32 overlay_fdt_size, int *ovcs_id) 32 + { 33 + kunit_skip(test, "requires CONFIG_OF and CONFIG_OF_OVERLAY and CONFIG_OF_EARLY_FLATTREE for root node"); 34 + return -EINVAL; 35 + } 36 + 37 + #endif 38 + 39 + /** 40 + * __of_overlay_apply_kunit() - Test managed of_overlay_fdt_apply() variant 41 + * @test: test context 42 + * @overlay_begin: start address of overlay to apply 43 + * @overlay_end: end address of overlay to apply 44 + * 45 + * This is mostly internal API. See of_overlay_apply_kunit() for the wrapper 46 + * that makes this easier to use. 47 + * 48 + * Similar to of_overlay_fdt_apply(), except the overlay is managed by the test 49 + * case and is automatically removed with of_overlay_remove() after the test 50 + * case concludes. 51 + * 52 + * Return: 0 on success, negative errno on failure 53 + */ 54 + static inline int __of_overlay_apply_kunit(struct kunit *test, 55 + u8 *overlay_begin, 56 + const u8 *overlay_end) 57 + { 58 + int unused; 59 + 60 + return of_overlay_fdt_apply_kunit(test, overlay_begin, 61 + overlay_end - overlay_begin, 62 + &unused); 63 + } 64 + 65 + /** 66 + * of_overlay_apply_kunit() - Test managed of_overlay_fdt_apply() for built-in overlays 67 + * @test: test context 68 + * @overlay_name: name of overlay to apply 69 + * 70 + * This macro is used to apply a device tree overlay built with the 71 + * cmd_dt_S_dtbo rule in scripts/Makefile.lib that has been compiled into the 72 + * kernel image or KUnit test module. The overlay is automatically removed when 73 + * the test is finished. 74 + * 75 + * Unit tests that need device tree nodes should compile an overlay file with 76 + * @overlay_name\.dtbo.o in their Makefile along with their unit test and then 77 + * load the overlay during their test. The @overlay_name matches the filename 78 + * of the overlay without the dtbo filename extension. If CONFIG_OF_OVERLAY is 79 + * not enabled, the @test will be skipped. 80 + * 81 + * In the Makefile 82 + * 83 + * .. code-block:: none 84 + * 85 + * obj-$(CONFIG_OF_OVERLAY_KUNIT_TEST) += overlay_test.o kunit_overlay_test.dtbo.o 86 + * 87 + * In the test 88 + * 89 + * .. code-block:: c 90 + * 91 + * static void of_overlay_kunit_of_overlay_apply(struct kunit *test) 92 + * { 93 + * struct device_node *np; 94 + * 95 + * KUNIT_ASSERT_EQ(test, 0, 96 + * of_overlay_apply_kunit(test, kunit_overlay_test)); 97 + * 98 + * np = of_find_node_by_name(NULL, "test-kunit"); 99 + * KUNIT_EXPECT_NOT_ERR_OR_NULL(test, np); 100 + * of_node_put(np); 101 + * } 102 + * 103 + * Return: 0 on success, negative errno on failure. 104 + */ 105 + #define of_overlay_apply_kunit(test, overlay_name) \ 106 + ({ \ 107 + extern uint8_t __dtbo_##overlay_name##_begin[]; \ 108 + extern uint8_t __dtbo_##overlay_name##_end[]; \ 109 + \ 110 + __of_overlay_apply_kunit((test), \ 111 + __dtbo_##overlay_name##_begin, \ 112 + __dtbo_##overlay_name##_end); \ 113 + }) 114 + 115 + #endif