]> git.proxmox.com Git - mirror_spl-debian.git/blob - module/splat/splat-generic.c
New upstream version 0.7.2
[mirror_spl-debian.git] / module / splat / splat-generic.c
1 /*****************************************************************************\
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
6 * UCRL-CODE-235197
7 *
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://zfsonlinux.org/>.
10 *
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 *
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting LAyer Tests (SPLAT) Generic Tests.
25 \*****************************************************************************/
26
27 #include <sys/sunddi.h>
28 #include <linux/math64_compat.h>
29 #include "splat-internal.h"
30
31 #define SPLAT_GENERIC_NAME "generic"
32 #define SPLAT_GENERIC_DESC "Kernel Generic Tests"
33
34 #define SPLAT_GENERIC_TEST1_ID 0x0d01
35 #define SPLAT_GENERIC_TEST1_NAME "ddi_strtoul"
36 #define SPLAT_GENERIC_TEST1_DESC "ddi_strtoul Test"
37
38 #define SPLAT_GENERIC_TEST2_ID 0x0d02
39 #define SPLAT_GENERIC_TEST2_NAME "ddi_strtol"
40 #define SPLAT_GENERIC_TEST2_DESC "ddi_strtol Test"
41
42 #define SPLAT_GENERIC_TEST3_ID 0x0d03
43 #define SPLAT_GENERIC_TEST3_NAME "ddi_strtoull"
44 #define SPLAT_GENERIC_TEST3_DESC "ddi_strtoull Test"
45
46 #define SPLAT_GENERIC_TEST4_ID 0x0d04
47 #define SPLAT_GENERIC_TEST4_NAME "ddi_strtoll"
48 #define SPLAT_GENERIC_TEST4_DESC "ddi_strtoll Test"
49
50 # define SPLAT_GENERIC_TEST5_ID 0x0d05
51 # define SPLAT_GENERIC_TEST5_NAME "udivdi3"
52 # define SPLAT_GENERIC_TEST5_DESC "Unsigned Div-64 Test"
53
54 # define SPLAT_GENERIC_TEST6_ID 0x0d06
55 # define SPLAT_GENERIC_TEST6_NAME "divdi3"
56 # define SPLAT_GENERIC_TEST6_DESC "Signed Div-64 Test"
57
58 #define STR_POS "123456789"
59 #define STR_NEG "-123456789"
60 #define STR_BASE "0xabcdef"
61 #define STR_RANGE_MAX "10000000000000000"
62 #define STR_RANGE_MIN "-10000000000000000"
63 #define STR_INVAL1 "12345U"
64 #define STR_INVAL2 "invald"
65
66 #define VAL_POS 123456789
67 #define VAL_NEG -123456789
68 #define VAL_BASE 0xabcdef
69 #define VAL_INVAL1 12345U
70
71 #define define_generic_msg_strtox(type, valtype) \
72 static void \
73 generic_msg_strto##type(struct file *file, char *msg, int rc, int *err, \
74 const char *s, valtype d, char *endptr) \
75 { \
76 splat_vprint(file, SPLAT_GENERIC_TEST1_NAME, \
77 "%s (%d) %s: %s == %lld, 0x%p\n", \
78 rc ? "Fail" : "Pass", *err, msg, s, \
79 (unsigned long long)d, endptr); \
80 *err = rc; \
81 }
82
83 define_generic_msg_strtox(ul, unsigned long);
84 define_generic_msg_strtox(l, long);
85 define_generic_msg_strtox(ull, unsigned long long);
86 define_generic_msg_strtox(ll, long long);
87
88 #define define_splat_generic_test_strtox(type, valtype) \
89 static int \
90 splat_generic_test_strto##type(struct file *file, void *arg) \
91 { \
92 int rc, rc1, rc2, rc3, rc4, rc5, rc6, rc7; \
93 char str[20], *endptr; \
94 valtype r; \
95 \
96 /* Positive value: expect success */ \
97 r = 0; \
98 rc = 1; \
99 endptr = NULL; \
100 rc1 = ddi_strto##type(STR_POS, &endptr, 10, &r); \
101 if (rc1 == 0 && r == VAL_POS && endptr && *endptr == '\0') \
102 rc = 0; \
103 \
104 generic_msg_strto##type(file, "positive", rc , &rc1, \
105 STR_POS, r, endptr); \
106 \
107 /* Negative value: expect success */ \
108 r = 0; \
109 rc = 1; \
110 endptr = NULL; \
111 strcpy(str, STR_NEG); \
112 rc2 = ddi_strto##type(str, &endptr, 10, &r); \
113 if (#type[0] == 'u') { \
114 if (rc2 == 0 && r == 0 && endptr == str) \
115 rc = 0; \
116 } else { \
117 if (rc2 == 0 && r == VAL_NEG && \
118 endptr && *endptr == '\0') \
119 rc = 0; \
120 } \
121 \
122 generic_msg_strto##type(file, "negative", rc, &rc2, \
123 STR_NEG, r, endptr); \
124 \
125 /* Non decimal base: expect sucess */ \
126 r = 0; \
127 rc = 1; \
128 endptr = NULL; \
129 rc3 = ddi_strto##type(STR_BASE, &endptr, 0, &r); \
130 if (rc3 == 0 && r == VAL_BASE && endptr && *endptr == '\0') \
131 rc = 0; \
132 \
133 generic_msg_strto##type(file, "base", rc, &rc3, \
134 STR_BASE, r, endptr); \
135 \
136 /* Max out of range: failure expected, r unchanged */ \
137 r = 0; \
138 rc = 1; \
139 endptr = NULL; \
140 rc4 = ddi_strto##type(STR_RANGE_MAX, &endptr, 16, &r); \
141 if (rc4 == ERANGE && r == 0 && endptr == NULL) \
142 rc = 0; \
143 \
144 generic_msg_strto##type(file, "max", rc, &rc4, \
145 STR_RANGE_MAX, r, endptr); \
146 \
147 /* Min out of range: failure expected, r unchanged */ \
148 r = 0; \
149 rc = 1; \
150 endptr = NULL; \
151 strcpy(str, STR_RANGE_MIN); \
152 rc5 = ddi_strto##type(str, &endptr, 16, &r); \
153 if (#type[0] == 'u') { \
154 if (rc5 == 0 && r == 0 && endptr == str) \
155 rc = 0; \
156 } else { \
157 if (rc5 == ERANGE && r == 0 && endptr == NULL) \
158 rc = 0; \
159 } \
160 \
161 generic_msg_strto##type(file, "min", rc, &rc5, \
162 STR_RANGE_MIN, r, endptr); \
163 \
164 /* Invalid string: success expected, endptr == 'U' */ \
165 r = 0; \
166 rc = 1; \
167 endptr = NULL; \
168 rc6 = ddi_strto##type(STR_INVAL1, &endptr, 10, &r); \
169 if (rc6 == 0 && r == VAL_INVAL1 && endptr && *endptr == 'U') \
170 rc = 0; \
171 \
172 generic_msg_strto##type(file, "invalid", rc, &rc6, \
173 STR_INVAL1, r, endptr); \
174 \
175 /* Invalid string: failure expected, endptr == str */ \
176 r = 0; \
177 rc = 1; \
178 endptr = NULL; \
179 strcpy(str, STR_INVAL2); \
180 rc7 = ddi_strto##type(str, &endptr, 10, &r); \
181 if (rc7 == 0 && r == 0 && endptr == str) \
182 rc = 0; \
183 \
184 generic_msg_strto##type(file, "invalid", rc, &rc7, \
185 STR_INVAL2, r, endptr); \
186 \
187 return (rc1 || rc2 || rc3 || rc4 || rc5 || rc6 || rc7) ? \
188 -EINVAL : 0; \
189 }
190
191 define_splat_generic_test_strtox(ul, unsigned long);
192 define_splat_generic_test_strtox(l, long);
193 define_splat_generic_test_strtox(ull, unsigned long long);
194 define_splat_generic_test_strtox(ll, long long);
195
196 /*
197 * The entries in the table are used in all combinations and the
198 * return value is checked to ensure it is range. On 32-bit
199 * systems __udivdi3 will be invoked for the 64-bit division.
200 * On 64-bit system the native 64-bit divide will be used so
201 * __udivdi3 isn't used but we might as well stil run the test.
202 */
203 static int
204 splat_generic_test_udivdi3(struct file *file, void *arg)
205 {
206 const uint64_t tabu[] = {
207 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
208 10, 11, 12, 13, 14, 15, 16, 1000, 2003,
209 32765, 32766, 32767, 32768, 32769, 32760,
210 65533, 65534, 65535, 65536, 65537, 65538,
211 0x7ffffffeULL, 0x7fffffffULL, 0x80000000ULL, 0x80000001ULL,
212 0x7000000000000000ULL, 0x7000000080000000ULL, 0x7000000080000001ULL,
213 0x7fffffffffffffffULL, 0x7fffffff8fffffffULL, 0x7fffffff8ffffff1ULL,
214 0x7fffffff00000000ULL, 0x7fffffff80000000ULL, 0x7fffffff00000001ULL,
215 0x8000000000000000ULL, 0x8000000080000000ULL, 0x8000000080000001ULL,
216 0xc000000000000000ULL, 0xc000000080000000ULL, 0xc000000080000001ULL,
217 0xfffffffffffffffdULL, 0xfffffffffffffffeULL, 0xffffffffffffffffULL,
218 };
219 uint64_t uu, vu, qu, ru;
220 int n, i, j, errors = 0;
221
222 splat_vprint(file, SPLAT_GENERIC_TEST5_NAME, "%s",
223 "Testing unsigned 64-bit division.\n");
224 n = sizeof(tabu) / sizeof(tabu[0]);
225 for (i = 0; i < n; i++) {
226 for (j = 1; j < n; j++) {
227 uu = tabu[i];
228 vu = tabu[j];
229 qu = uu / vu; /* __udivdi3 */
230 ru = uu - qu * vu;
231 if (qu > uu || ru >= vu) {
232 splat_vprint(file, SPLAT_GENERIC_TEST5_NAME,
233 "%016llx/%016llx != %016llx rem %016llx\n",
234 uu, vu, qu, ru);
235 errors++;
236 }
237 }
238 }
239
240 if (errors) {
241 splat_vprint(file, SPLAT_GENERIC_TEST5_NAME,
242 "Failed %d/%d tests\n", errors, n * (n - 1));
243 return -ERANGE;
244 }
245
246 splat_vprint(file, SPLAT_GENERIC_TEST5_NAME,
247 "Passed all %d tests\n", n * (n - 1));
248
249 return 0;
250 }
251
252 /*
253 * The entries the table are used in all combinations, with + and - signs
254 * preceding them. The return value is checked to ensure it is range.
255 * On 32-bit systems __divdi3 will be invoked for the 64-bit division.
256 * On 64-bit system the native 64-bit divide will be used so __divdi3
257 * isn't used but we might as well stil run the test.
258 */
259 static int
260 splat_generic_test_divdi3(struct file *file, void *arg)
261 {
262 const int64_t tabs[] = {
263 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
264 10, 11, 12, 13, 14, 15, 16, 1000, 2003,
265 32765, 32766, 32767, 32768, 32769, 32760,
266 65533, 65534, 65535, 65536, 65537, 65538,
267 0x7ffffffeLL, 0x7fffffffLL, 0x80000000LL, 0x80000001LL,
268 0x7000000000000000LL, 0x7000000080000000LL, 0x7000000080000001LL,
269 0x7fffffffffffffffLL, 0x7fffffff8fffffffLL, 0x7fffffff8ffffff1LL,
270 0x7fffffff00000000LL, 0x7fffffff80000000LL, 0x7fffffff00000001LL,
271 0x0123456789abcdefLL, 0x00000000abcdef01LL, 0x0000000012345678LL,
272 #if BITS_PER_LONG == 32
273 0x8000000000000000LL, 0x8000000080000000LL, 0x8000000080000001LL,
274 #endif
275 };
276 int64_t u, v, q, r;
277 int n, i, j, k, errors = 0;
278
279 splat_vprint(file, SPLAT_GENERIC_TEST6_NAME, "%s",
280 "Testing signed 64-bit division.\n");
281 n = sizeof(tabs) / sizeof(tabs[0]);
282 for (i = 0; i < n; i++) {
283 for (j = 1; j < n; j++) {
284 for (k = 0; k <= 3; k++) {
285 u = (k & 1) ? -tabs[i] : tabs[i];
286 v = (k >= 2) ? -tabs[j] : tabs[j];
287
288 q = u / v; /* __divdi3 */
289 r = u - q * v;
290 if (abs64(q) > abs64(u) ||
291 abs64(r) >= abs64(v) ||
292 (r != 0 && (r ^ u) < 0)) {
293 splat_vprint(file,
294 SPLAT_GENERIC_TEST6_NAME,
295 "%016llx/%016llx != %016llx "
296 "rem %016llx\n", u, v, q, r);
297 errors++;
298 }
299 }
300 }
301 }
302
303 if (errors) {
304 splat_vprint(file, SPLAT_GENERIC_TEST6_NAME,
305 "Failed %d/%d tests\n", errors, n * (n - 1));
306 return -ERANGE;
307 }
308
309 splat_vprint(file, SPLAT_GENERIC_TEST6_NAME,
310 "Passed all %d tests\n", n * (n - 1));
311
312 return 0;
313 }
314
315 splat_subsystem_t *
316 splat_generic_init(void)
317 {
318 splat_subsystem_t *sub;
319
320 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
321 if (sub == NULL)
322 return NULL;
323
324 memset(sub, 0, sizeof(*sub));
325 strncpy(sub->desc.name, SPLAT_GENERIC_NAME, SPLAT_NAME_SIZE);
326 strncpy(sub->desc.desc, SPLAT_GENERIC_DESC, SPLAT_DESC_SIZE);
327 INIT_LIST_HEAD(&sub->subsystem_list);
328 INIT_LIST_HEAD(&sub->test_list);
329 spin_lock_init(&sub->test_lock);
330 sub->desc.id = SPLAT_SUBSYSTEM_GENERIC;
331
332 splat_test_init(sub, SPLAT_GENERIC_TEST1_NAME, SPLAT_GENERIC_TEST1_DESC,
333 SPLAT_GENERIC_TEST1_ID, splat_generic_test_strtoul);
334 splat_test_init(sub, SPLAT_GENERIC_TEST2_NAME, SPLAT_GENERIC_TEST2_DESC,
335 SPLAT_GENERIC_TEST2_ID, splat_generic_test_strtol);
336 splat_test_init(sub, SPLAT_GENERIC_TEST3_NAME, SPLAT_GENERIC_TEST3_DESC,
337 SPLAT_GENERIC_TEST3_ID, splat_generic_test_strtoull);
338 splat_test_init(sub, SPLAT_GENERIC_TEST4_NAME, SPLAT_GENERIC_TEST4_DESC,
339 SPLAT_GENERIC_TEST4_ID, splat_generic_test_strtoll);
340 splat_test_init(sub, SPLAT_GENERIC_TEST5_NAME, SPLAT_GENERIC_TEST5_DESC,
341 SPLAT_GENERIC_TEST5_ID, splat_generic_test_udivdi3);
342 splat_test_init(sub, SPLAT_GENERIC_TEST6_NAME, SPLAT_GENERIC_TEST6_DESC,
343 SPLAT_GENERIC_TEST6_ID, splat_generic_test_divdi3);
344
345 return sub;
346 }
347
348 void
349 splat_generic_fini(splat_subsystem_t *sub)
350 {
351 ASSERT(sub);
352
353 splat_test_fini(sub, SPLAT_GENERIC_TEST6_ID);
354 splat_test_fini(sub, SPLAT_GENERIC_TEST5_ID);
355 splat_test_fini(sub, SPLAT_GENERIC_TEST4_ID);
356 splat_test_fini(sub, SPLAT_GENERIC_TEST3_ID);
357 splat_test_fini(sub, SPLAT_GENERIC_TEST2_ID);
358 splat_test_fini(sub, SPLAT_GENERIC_TEST1_ID);
359
360 kfree(sub);
361 }
362
363 int
364 splat_generic_id(void)
365 {
366 return SPLAT_SUBSYSTEM_GENERIC;
367 }