Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2021  Maciej W. Rozycki
  4 */
  5
  6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  7
  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>
 14
 15#include <asm/div64.h>
 16
 17#define TEST_DIV64_N_ITER 1024
 18
 19static const u64 test_div64_dividends[] = {
 20	0x00000000ab275080,
 21	0x0000000fe73c1959,
 22	0x000000e54c0a74b1,
 23	0x00000d4398ff1ef9,
 24	0x0000a18c2ee1c097,
 25	0x00079fb80b072e4a,
 26	0x0072db27380dd689,
 27	0x0842f488162e2284,
 28	0xf66745411d8ab063,
 29	0xfffffffffffffffb,
 30	0xfffffffffffffffc,
 31	0xffffffffffffffff,
 32};
 33#define SIZE_DIV64_DIVIDENDS ARRAY_SIZE(test_div64_dividends)
 34
 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
 47
 48static const u32 test_div64_divisors[] = {
 49	TEST_DIV64_DIVISOR_0,
 50	TEST_DIV64_DIVISOR_1,
 51	TEST_DIV64_DIVISOR_2,
 52	TEST_DIV64_DIVISOR_3,
 53	TEST_DIV64_DIVISOR_4,
 54	TEST_DIV64_DIVISOR_5,
 55	TEST_DIV64_DIVISOR_6,
 56	TEST_DIV64_DIVISOR_7,
 57	TEST_DIV64_DIVISOR_8,
 58	TEST_DIV64_DIVISOR_9,
 59	TEST_DIV64_DIVISOR_A,
 60	TEST_DIV64_DIVISOR_B,
 61};
 62#define SIZE_DIV64_DIVISORS ARRAY_SIZE(test_div64_divisors)
 63
 64static const struct {
 65	u64 quotient;
 66	u32 remainder;
 67} test_div64_results[SIZE_DIV64_DIVIDENDS][SIZE_DIV64_DIVISORS] = {
 68	{
 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 },
 81	}, {
 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 },
 94	}, {
 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 },
107	}, {
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 },
120	}, {
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 },
133	}, {
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 },
146	}, {
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 },
159	}, {
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 },
172	}, {
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 },
185	}, {
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 },
198	}, {
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 },
211	}, {
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 },
224	},
225};
226
227static inline bool test_div64_verify(u64 quotient, u32 remainder, int i, int j)
228{
229	return (quotient == test_div64_results[i][j].quotient &&
230		remainder == test_div64_results[i][j].remainder);
231}
232
233/*
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.
237 */
238#define test_div64_one(dividend, divisor, i, j) ({			\
239	bool result = true;						\
240	u64 quotient;							\
241	u32 remainder;							\
242									\
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);		\
251		result = false;						\
252	}								\
253	result;								\
254})
255
256/*
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.
260 */
261static bool __init test_div64(void)
262{
263	u64 dividend;
264	int i, j;
265
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))
269			return false;
270		if (!test_div64_one(dividend, TEST_DIV64_DIVISOR_1, i, 1))
271			return false;
272		if (!test_div64_one(dividend, TEST_DIV64_DIVISOR_2, i, 2))
273			return false;
274		if (!test_div64_one(dividend, TEST_DIV64_DIVISOR_3, i, 3))
275			return false;
276		if (!test_div64_one(dividend, TEST_DIV64_DIVISOR_4, i, 4))
277			return false;
278		if (!test_div64_one(dividend, TEST_DIV64_DIVISOR_5, i, 5))
279			return false;
280		if (!test_div64_one(dividend, TEST_DIV64_DIVISOR_6, i, 6))
281			return false;
282		if (!test_div64_one(dividend, TEST_DIV64_DIVISOR_7, i, 7))
283			return false;
284		if (!test_div64_one(dividend, TEST_DIV64_DIVISOR_8, i, 8))
285			return false;
286		if (!test_div64_one(dividend, TEST_DIV64_DIVISOR_9, i, 9))
287			return false;
288		if (!test_div64_one(dividend, TEST_DIV64_DIVISOR_A, i, 10))
289			return false;
290		if (!test_div64_one(dividend, TEST_DIV64_DIVISOR_B, i, 11))
291			return false;
292		for (j = 0; j < SIZE_DIV64_DIVISORS; j++) {
293			if (!test_div64_one(dividend, test_div64_divisors[j],
294					    i, j))
295				return false;
296		}
297	}
298	return true;
299}
300
301static int __init test_div64_init(void)
302{
303	struct timespec64 ts, ts0, ts1;
304	int i;
305
306	pr_info("Starting 64bit/32bit division and modulo test\n");
307	ktime_get_ts64(&ts0);
308
309	for (i = 0; i < TEST_DIV64_N_ITER; i++)
310		if (!test_div64())
311			break;
312
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);
317
318	return 0;
319}
320
321static void __exit test_div64_exit(void)
322{
323}
324
325module_init(test_div64_init);
326module_exit(test_div64_exit);
327
328MODULE_AUTHOR("Maciej W. Rozycki <macro@orcam.me.uk>");
329MODULE_LICENSE("GPL");
330MODULE_DESCRIPTION("64bit/32bit division and modulo test module");