1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2021 Maciej W. Rozycki
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8 #include <linux/init.h>
9 #include <linux/ktime.h>
10 #include <linux/module.h>
11 #include <linux/printk.h>
12 #include <linux/time64.h>
13 #include <linux/types.h>
15 #include <asm/div64.h>
17 #define TEST_DIV64_N_ITER 1024
19 static const u64 test_div64_dividends
[] = {
33 #define SIZE_DIV64_DIVIDENDS ARRAY_SIZE(test_div64_dividends)
35 #define TEST_DIV64_DIVISOR_0 0x00000009
36 #define TEST_DIV64_DIVISOR_1 0x0000007c
37 #define TEST_DIV64_DIVISOR_2 0x00000204
38 #define TEST_DIV64_DIVISOR_3 0x0000cb5b
39 #define TEST_DIV64_DIVISOR_4 0x00010000
40 #define TEST_DIV64_DIVISOR_5 0x0008a880
41 #define TEST_DIV64_DIVISOR_6 0x003fd3ae
42 #define TEST_DIV64_DIVISOR_7 0x0b658fac
43 #define TEST_DIV64_DIVISOR_8 0x80000001
44 #define TEST_DIV64_DIVISOR_9 0xdc08b349
45 #define TEST_DIV64_DIVISOR_A 0xfffffffe
46 #define TEST_DIV64_DIVISOR_B 0xffffffff
48 static const u32 test_div64_divisors
[] = {
62 #define SIZE_DIV64_DIVISORS ARRAY_SIZE(test_div64_divisors)
67 } test_div64_results
[SIZE_DIV64_DIVIDENDS
][SIZE_DIV64_DIVISORS
] = {
69 { 0x0000000013045e47, 0x00000001 },
70 { 0x000000000161596c, 0x00000030 },
71 { 0x000000000054e9d4, 0x00000130 },
72 { 0x000000000000d776, 0x0000278e },
73 { 0x000000000000ab27, 0x00005080 },
74 { 0x00000000000013c4, 0x0004ce80 },
75 { 0x00000000000002ae, 0x001e143c },
76 { 0x000000000000000f, 0x0033e56c },
77 { 0x0000000000000001, 0x2b27507f },
78 { 0x0000000000000000, 0xab275080 },
79 { 0x0000000000000000, 0xab275080 },
80 { 0x0000000000000000, 0xab275080 },
82 { 0x00000001c45c02d1, 0x00000000 },
83 { 0x0000000020d5213c, 0x00000049 },
84 { 0x0000000007e3d65f, 0x000001dd },
85 { 0x0000000000140531, 0x000065ee },
86 { 0x00000000000fe73c, 0x00001959 },
87 { 0x000000000001d637, 0x0004e5d9 },
88 { 0x0000000000003fc9, 0x000713bb },
89 { 0x0000000000000165, 0x029abe7d },
90 { 0x000000000000001f, 0x673c193a },
91 { 0x0000000000000012, 0x6e9f7e37 },
92 { 0x000000000000000f, 0xe73c1977 },
93 { 0x000000000000000f, 0xe73c1968 },
95 { 0x000000197a3a0cf7, 0x00000002 },
96 { 0x00000001d9632e5c, 0x00000021 },
97 { 0x0000000071c28039, 0x000001cd },
98 { 0x000000000120a844, 0x0000b885 },
99 { 0x0000000000e54c0a, 0x000074b1 },
100 { 0x00000000001a7bb3, 0x00072331 },
101 { 0x00000000000397ad, 0x0002c61b },
102 { 0x000000000000141e, 0x06ea2e89 },
103 { 0x00000000000001ca, 0x4c0a72e7 },
104 { 0x000000000000010a, 0xab002ad7 },
105 { 0x00000000000000e5, 0x4c0a767b },
106 { 0x00000000000000e5, 0x4c0a7596 },
108 { 0x0000017949e37538, 0x00000001 },
109 { 0x0000001b62441f37, 0x00000055 },
110 { 0x0000000694a3391d, 0x00000085 },
111 { 0x0000000010b2a5d2, 0x0000a753 },
112 { 0x000000000d4398ff, 0x00001ef9 },
113 { 0x0000000001882ec6, 0x0005cbf9 },
114 { 0x000000000035333b, 0x0017abdf },
115 { 0x00000000000129f1, 0x0ab4520d },
116 { 0x0000000000001a87, 0x18ff0472 },
117 { 0x0000000000000f6e, 0x8ac0ce9b },
118 { 0x0000000000000d43, 0x98ff397f },
119 { 0x0000000000000d43, 0x98ff2c3c },
121 { 0x000011f321a74e49, 0x00000006 },
122 { 0x0000014d8481d211, 0x0000005b },
123 { 0x0000005025cbd92d, 0x000001e3 },
124 { 0x00000000cb5e71e3, 0x000043e6 },
125 { 0x00000000a18c2ee1, 0x0000c097 },
126 { 0x0000000012a88828, 0x00036c97 },
127 { 0x000000000287f16f, 0x002c2a25 },
128 { 0x00000000000e2cc7, 0x02d581e3 },
129 { 0x0000000000014318, 0x2ee07d7f },
130 { 0x000000000000bbf4, 0x1ba08c03 },
131 { 0x000000000000a18c, 0x2ee303af },
132 { 0x000000000000a18c, 0x2ee26223 },
134 { 0x0000d8db8f72935d, 0x00000005 },
135 { 0x00000fbd5aed7a2e, 0x00000002 },
136 { 0x000003c84b6ea64a, 0x00000122 },
137 { 0x0000000998fa8829, 0x000044b7 },
138 { 0x000000079fb80b07, 0x00002e4a },
139 { 0x00000000e16b20fa, 0x0002a14a },
140 { 0x000000001e940d22, 0x00353b2e },
141 { 0x0000000000ab40ac, 0x06fba6ba },
142 { 0x00000000000f3f70, 0x0af7eeda },
143 { 0x000000000008debd, 0x72d98365 },
144 { 0x0000000000079fb8, 0x0b166dba },
145 { 0x0000000000079fb8, 0x0b0ece02 },
147 { 0x000cc3045b8fc281, 0x00000000 },
148 { 0x0000ed1f48b5c9fc, 0x00000079 },
149 { 0x000038fb9c63406a, 0x000000e1 },
150 { 0x000000909705b825, 0x00000a62 },
151 { 0x00000072db27380d, 0x0000d689 },
152 { 0x0000000d43fce827, 0x00082b09 },
153 { 0x00000001ccaba11a, 0x0037e8dd },
154 { 0x000000000a13f729, 0x0566dffd },
155 { 0x0000000000e5b64e, 0x3728203b },
156 { 0x000000000085a14b, 0x23d36726 },
157 { 0x000000000072db27, 0x38f38cd7 },
158 { 0x000000000072db27, 0x3880b1b0 },
160 { 0x00eafeb9c993592b, 0x00000001 },
161 { 0x00110e5befa9a991, 0x00000048 },
162 { 0x00041947b4a1d36a, 0x000000dc },
163 { 0x00000a6679327311, 0x0000c079 },
164 { 0x00000842f488162e, 0x00002284 },
165 { 0x000000f4459740fc, 0x00084484 },
166 { 0x0000002122c47bf9, 0x002ca446 },
167 { 0x00000000b9936290, 0x004979c4 },
168 { 0x000000001085e910, 0x05a83974 },
169 { 0x00000000099ca89d, 0x9db446bf },
170 { 0x000000000842f488, 0x26b40b94 },
171 { 0x000000000842f488, 0x1e71170c },
173 { 0x1b60cece589da1d2, 0x00000001 },
174 { 0x01fcb42be1453f5b, 0x0000004f },
175 { 0x007a3f2457df0749, 0x0000013f },
176 { 0x0001363130e3ec7b, 0x000017aa },
177 { 0x0000f66745411d8a, 0x0000b063 },
178 { 0x00001c757dfab350, 0x00048863 },
179 { 0x000003dc4979c652, 0x00224ea7 },
180 { 0x000000159edc3144, 0x06409ab3 },
181 { 0x00000001ecce8a7e, 0x30bc25e5 },
182 { 0x000000011eadfee3, 0xa99c48a8 },
183 { 0x00000000f6674543, 0x0a593ae9 },
184 { 0x00000000f6674542, 0x13f1f5a5 },
186 { 0x1c71c71c71c71c71, 0x00000002 },
187 { 0x0210842108421084, 0x0000000b },
188 { 0x007f01fc07f01fc0, 0x000000fb },
189 { 0x00014245eabf1f9a, 0x0000a63d },
190 { 0x0000ffffffffffff, 0x0000fffb },
191 { 0x00001d913cecc509, 0x0007937b },
192 { 0x00000402c70c678f, 0x0005bfc9 },
193 { 0x00000016766cb70b, 0x045edf97 },
194 { 0x00000001fffffffb, 0x80000000 },
195 { 0x0000000129d84b3a, 0xa2e8fe71 },
196 { 0x0000000100000001, 0xfffffffd },
197 { 0x0000000100000000, 0xfffffffb },
199 { 0x1c71c71c71c71c71, 0x00000003 },
200 { 0x0210842108421084, 0x0000000c },
201 { 0x007f01fc07f01fc0, 0x000000fc },
202 { 0x00014245eabf1f9a, 0x0000a63e },
203 { 0x0000ffffffffffff, 0x0000fffc },
204 { 0x00001d913cecc509, 0x0007937c },
205 { 0x00000402c70c678f, 0x0005bfca },
206 { 0x00000016766cb70b, 0x045edf98 },
207 { 0x00000001fffffffc, 0x00000000 },
208 { 0x0000000129d84b3a, 0xa2e8fe72 },
209 { 0x0000000100000002, 0x00000000 },
210 { 0x0000000100000000, 0xfffffffc },
212 { 0x1c71c71c71c71c71, 0x00000006 },
213 { 0x0210842108421084, 0x0000000f },
214 { 0x007f01fc07f01fc0, 0x000000ff },
215 { 0x00014245eabf1f9a, 0x0000a641 },
216 { 0x0000ffffffffffff, 0x0000ffff },
217 { 0x00001d913cecc509, 0x0007937f },
218 { 0x00000402c70c678f, 0x0005bfcd },
219 { 0x00000016766cb70b, 0x045edf9b },
220 { 0x00000001fffffffc, 0x00000003 },
221 { 0x0000000129d84b3a, 0xa2e8fe75 },
222 { 0x0000000100000002, 0x00000003 },
223 { 0x0000000100000001, 0x00000000 },
227 static inline bool test_div64_verify(u64 quotient
, u32 remainder
, int i
, int j
)
229 return (quotient
== test_div64_results
[i
][j
].quotient
&&
230 remainder
== test_div64_results
[i
][j
].remainder
);
234 * This needs to be a macro, because we don't want to rely on the compiler
235 * to do constant propagation, and `do_div' may take a different path for
236 * constants, so we do want to verify that as well.
238 #define test_div64_one(dividend, divisor, i, j) ({ \
239 bool result = true; \
243 quotient = dividend; \
244 remainder = do_div(quotient, divisor); \
245 if (!test_div64_verify(quotient, remainder, i, j)) { \
246 pr_err("ERROR: %016llx / %08x => %016llx,%08x\n", \
247 dividend, divisor, quotient, remainder); \
248 pr_err("ERROR: expected value => %016llx,%08x\n",\
249 test_div64_results[i][j].quotient, \
250 test_div64_results[i][j].remainder); \
257 * Run calculation for the same divisor value expressed as a constant
258 * and as a variable, so as to verify the implementation for both cases
259 * should they be handled by different code execution paths.
261 static bool __init
test_div64(void)
266 for (i
= 0; i
< SIZE_DIV64_DIVIDENDS
; i
++) {
267 dividend
= test_div64_dividends
[i
];
268 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_0
, i
, 0))
270 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_1
, i
, 1))
272 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_2
, i
, 2))
274 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_3
, i
, 3))
276 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_4
, i
, 4))
278 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_5
, i
, 5))
280 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_6
, i
, 6))
282 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_7
, i
, 7))
284 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_8
, i
, 8))
286 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_9
, i
, 9))
288 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_A
, i
, 10))
290 if (!test_div64_one(dividend
, TEST_DIV64_DIVISOR_B
, i
, 11))
292 for (j
= 0; j
< SIZE_DIV64_DIVISORS
; j
++) {
293 if (!test_div64_one(dividend
, test_div64_divisors
[j
],
301 static int __init
test_div64_init(void)
303 struct timespec64 ts
, ts0
, ts1
;
306 pr_info("Starting 64bit/32bit division and modulo test\n");
307 ktime_get_ts64(&ts0
);
309 for (i
= 0; i
< TEST_DIV64_N_ITER
; i
++)
313 ktime_get_ts64(&ts1
);
314 ts
= timespec64_sub(ts1
, ts0
);
315 pr_info("Completed 64bit/32bit division and modulo test, "
316 "%llu.%09lus elapsed\n", ts
.tv_sec
, ts
.tv_nsec
);
321 static void __exit
test_div64_exit(void)
325 module_init(test_div64_init
);
326 module_exit(test_div64_exit
);
328 MODULE_AUTHOR("Maciej W. Rozycki <macro@orcam.me.uk>");
329 MODULE_LICENSE("GPL");
330 MODULE_DESCRIPTION("64bit/32bit division and modulo test module");