test_div64.c 10 KB

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