[PATCH] tests: provide a word-at-a-time test implementation

From: Sven Schnelle
Date: Mon Oct 09 2023 - 08:05:18 EST


Add some basic tests to test the correctness of has_zero() and
find_zero().

Signed-off-by: Sven Schnelle <svens@xxxxxxxxxxxxx>
---
lib/Kconfig.debug | 11 +++++++
lib/Makefile | 1 +
lib/test_word-at-a-time.c | 62 +++++++++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+)
create mode 100644 lib/test_word-at-a-time.c

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index fa307f93fa2e..f7a4df3054ac 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2791,6 +2791,17 @@ config SIPHASH_KUNIT_TEST
This is intended to help people writing architecture-specific
optimized versions. If unsure, say N.

+config WORDATATIME_KUNIT_TEST
+ tristate "KUnit test word-at-a-time implementation at runtime" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Enable this option to test the kernel's word-at-a-time (<asm/word-at-a-time.h>)
+ functions on boot (or module load).
+
+ This is intended to help people writing architecture-specific
+ optimized versions. If unsure, say N.
+
config TEST_UDELAY
tristate "udelay test driver"
help
diff --git a/lib/Makefile b/lib/Makefile
index 740109b6e2c8..b3bc6a698896 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -402,6 +402,7 @@ obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o
obj-$(CONFIG_STRCAT_KUNIT_TEST) += strcat_kunit.o
obj-$(CONFIG_STRSCPY_KUNIT_TEST) += strscpy_kunit.o
obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o
+obj-$(CONFIG_WORDATATIME_KUNIT_TEST) += test_word-at-a-time.o

obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o

diff --git a/lib/test_word-at-a-time.c b/lib/test_word-at-a-time.c
new file mode 100644
index 000000000000..574303a4f913
--- /dev/null
+++ b/lib/test_word-at-a-time.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <kunit/test.h>
+#include <asm/word-at-a-time.h>
+
+static void test_wordatatime_has_zero(struct kunit *test)
+{
+ const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
+ unsigned long val, data;
+
+ val = -1UL;
+ KUNIT_ASSERT_FALSE(test, has_zero(val, &data, &constants));
+
+ for (int i = 0; i < BITS_PER_LONG; i += 8) {
+ val = ~(0xffUL << i);
+ KUNIT_ASSERT_TRUE(test, has_zero(val, &data, &constants));
+ }
+
+ for (int i = 0; i < BITS_PER_LONG; i++) {
+ val = ~(0x1UL << i);
+ KUNIT_ASSERT_FALSE(test, has_zero(val, &data, &constants));
+ }
+
+ for (int i = 0; i < BITS_PER_LONG; i++) {
+ val = 0x1UL << i;
+ KUNIT_ASSERT_TRUE(test, has_zero(val, &data, &constants));
+ }
+}
+
+static void test_wordatatime_find_zero(struct kunit *test)
+{
+ const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
+ unsigned long val, data;
+
+ for (int i = 0; i < BITS_PER_LONG; i += 8) {
+ val = ~(0xffUL << i);
+ KUNIT_ASSERT_TRUE(test, has_zero(val, &data, &constants));
+ data = prep_zero_mask(val, data, &constants);
+ data = create_zero_mask(data);
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ KUNIT_ASSERT_EQ(test, find_zero(data), (BITS_PER_LONG / 8 - 1) - (i / 8));
+#else
+ KUNIT_ASSERT_EQ(test, find_zero(data), i / 8);
+#endif
+ }
+}
+static struct kunit_case wordatatime_test_cases[] = {
+ KUNIT_CASE(test_wordatatime_has_zero),
+ KUNIT_CASE(test_wordatatime_find_zero),
+ {}
+};
+
+static struct kunit_suite wordatatime_test_suite = {
+ .name = "wordatatime_test",
+ .test_cases = wordatatime_test_cases,
+};
+
+kunit_test_suites(&wordatatime_test_suite);
+MODULE_LICENSE("GPL");
--
2.39.2