aboutsummaryrefslogtreecommitdiffstats
path: root/lib/test_bitfield.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2018-06-20 02:58:30 -0400
committerKalle Valo <kvalo@codeaurora.org>2018-06-27 11:58:49 -0400
commit0e2dc70e3d0d503b0cc9c5f74db3eb6db52c9e22 (patch)
tree58ea25d9c8ffb3fbc407ffce77823dccbc020af2 /lib/test_bitfield.c
parent37a3862e1238262e9866d5d66e5f5f9069cee3a1 (diff)
bitfield: add tests
Add tests for the bitfield helpers. The constant ones will all be folded to nothing by the compiler (if everything is correct in the header file), and the variable ones do some tests against open-coding the necessary shifts. A few test cases that should fail/warn compilation are provided under ifdef. Suggested-by: Andy Shevchenko <andy.shevchenko@gmail.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'lib/test_bitfield.c')
-rw-r--r--lib/test_bitfield.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/lib/test_bitfield.c b/lib/test_bitfield.c
new file mode 100644
index 000000000000..5b8f4108662d
--- /dev/null
+++ b/lib/test_bitfield.c
@@ -0,0 +1,168 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Test cases for bitfield helpers.
4 */
5
6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <linux/bitfield.h>
11
12#define CHECK_ENC_GET_U(tp, v, field, res) do { \
13 { \
14 u##tp _res; \
15 \
16 _res = u##tp##_encode_bits(v, field); \
17 if (_res != res) { \
18 pr_warn("u" #tp "_encode_bits(" #v ", " #field ") is 0x%llx != " #res "\n",\
19 (u64)_res); \
20 return -EINVAL; \
21 } \
22 if (u##tp##_get_bits(_res, field) != v) \
23 return -EINVAL; \
24 } \
25 } while (0)
26
27#define CHECK_ENC_GET_LE(tp, v, field, res) do { \
28 { \
29 __le##tp _res; \
30 \
31 _res = le##tp##_encode_bits(v, field); \
32 if (_res != cpu_to_le##tp(res)) { \
33 pr_warn("le" #tp "_encode_bits(" #v ", " #field ") is 0x%llx != 0x%llx\n",\
34 (u64)le##tp##_to_cpu(_res), \
35 (u64)(res)); \
36 return -EINVAL; \
37 } \
38 if (le##tp##_get_bits(_res, field) != v) \
39 return -EINVAL; \
40 } \
41 } while (0)
42
43#define CHECK_ENC_GET_BE(tp, v, field, res) do { \
44 { \
45 __be##tp _res; \
46 \
47 _res = be##tp##_encode_bits(v, field); \
48 if (_res != cpu_to_be##tp(res)) { \
49 pr_warn("be" #tp "_encode_bits(" #v ", " #field ") is 0x%llx != 0x%llx\n",\
50 (u64)be##tp##_to_cpu(_res), \
51 (u64)(res)); \
52 return -EINVAL; \
53 } \
54 if (be##tp##_get_bits(_res, field) != v) \
55 return -EINVAL; \
56 } \
57 } while (0)
58
59#define CHECK_ENC_GET(tp, v, field, res) do { \
60 CHECK_ENC_GET_U(tp, v, field, res); \
61 CHECK_ENC_GET_LE(tp, v, field, res); \
62 CHECK_ENC_GET_BE(tp, v, field, res); \
63 } while (0)
64
65static int test_constants(void)
66{
67 /*
68 * NOTE
69 * This whole function compiles (or at least should, if everything
70 * is going according to plan) to nothing after optimisation.
71 */
72
73 CHECK_ENC_GET(16, 1, 0x000f, 0x0001);
74 CHECK_ENC_GET(16, 3, 0x00f0, 0x0030);
75 CHECK_ENC_GET(16, 5, 0x0f00, 0x0500);
76 CHECK_ENC_GET(16, 7, 0xf000, 0x7000);
77 CHECK_ENC_GET(16, 14, 0x000f, 0x000e);
78 CHECK_ENC_GET(16, 15, 0x00f0, 0x00f0);
79
80 CHECK_ENC_GET_U(8, 1, 0x0f, 0x01);
81 CHECK_ENC_GET_U(8, 3, 0xf0, 0x30);
82 CHECK_ENC_GET_U(8, 14, 0x0f, 0x0e);
83 CHECK_ENC_GET_U(8, 15, 0xf0, 0xf0);
84
85 CHECK_ENC_GET(32, 1, 0x00000f00, 0x00000100);
86 CHECK_ENC_GET(32, 3, 0x0000f000, 0x00003000);
87 CHECK_ENC_GET(32, 5, 0x000f0000, 0x00050000);
88 CHECK_ENC_GET(32, 7, 0x00f00000, 0x00700000);
89 CHECK_ENC_GET(32, 14, 0x0f000000, 0x0e000000);
90 CHECK_ENC_GET(32, 15, 0xf0000000, 0xf0000000);
91
92 CHECK_ENC_GET(64, 1, 0x00000f0000000000ull, 0x0000010000000000ull);
93 CHECK_ENC_GET(64, 3, 0x0000f00000000000ull, 0x0000300000000000ull);
94 CHECK_ENC_GET(64, 5, 0x000f000000000000ull, 0x0005000000000000ull);
95 CHECK_ENC_GET(64, 7, 0x00f0000000000000ull, 0x0070000000000000ull);
96 CHECK_ENC_GET(64, 14, 0x0f00000000000000ull, 0x0e00000000000000ull);
97 CHECK_ENC_GET(64, 15, 0xf000000000000000ull, 0xf000000000000000ull);
98
99 return 0;
100}
101
102#define CHECK(tp, mask) do { \
103 u64 v; \
104 \
105 for (v = 0; v < 1 << hweight32(mask); v++) \
106 if (tp##_encode_bits(v, mask) != v << __ffs64(mask)) \
107 return -EINVAL; \
108 } while (0)
109
110static int test_variables(void)
111{
112 CHECK(u8, 0x0f);
113 CHECK(u8, 0xf0);
114 CHECK(u8, 0x38);
115
116 CHECK(u16, 0x0038);
117 CHECK(u16, 0x0380);
118 CHECK(u16, 0x3800);
119 CHECK(u16, 0x8000);
120
121 CHECK(u32, 0x80000000);
122 CHECK(u32, 0x7f000000);
123 CHECK(u32, 0x07e00000);
124 CHECK(u32, 0x00018000);
125
126 CHECK(u64, 0x8000000000000000ull);
127 CHECK(u64, 0x7f00000000000000ull);
128 CHECK(u64, 0x0001800000000000ull);
129 CHECK(u64, 0x0000000080000000ull);
130 CHECK(u64, 0x000000007f000000ull);
131 CHECK(u64, 0x0000000018000000ull);
132 CHECK(u64, 0x0000001f8000000ull);
133
134 return 0;
135}
136
137static int __init test_bitfields(void)
138{
139 int ret = test_constants();
140
141 if (ret) {
142 pr_warn("constant tests failed!\n");
143 return ret;
144 }
145
146 ret = test_variables();
147 if (ret) {
148 pr_warn("variable tests failed!\n");
149 return ret;
150 }
151
152#ifdef TEST_BITFIELD_COMPILE
153 /* these should fail compilation */
154 CHECK_ENC_GET(16, 16, 0x0f00, 0x1000);
155 u32_encode_bits(7, 0x06000000);
156
157 /* this should at least give a warning */
158 u16_encode_bits(0, 0x60000);
159#endif
160
161 pr_info("tests passed\n");
162
163 return 0;
164}
165module_init(test_bitfields)
166
167MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
168MODULE_LICENSE("GPL");