1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * selftest for sparc64's privileged ADI driver
4  *
5  * Author: Tom Hromatka <tom.hromatka@oracle.com>
6  */
7 #include <linux/kernel.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdarg.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/syscall.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <unistd.h>
18 
19 #include "../../kselftest.h"
20 
21 #define DEBUG_LEVEL_1_BIT	(0x0001)
22 #define DEBUG_LEVEL_2_BIT	(0x0002)
23 #define DEBUG_LEVEL_3_BIT	(0x0004)
24 #define DEBUG_LEVEL_4_BIT	(0x0008)
25 #define DEBUG_TIMING_BIT	(0x1000)
26 
27 /* bit mask of enabled bits to print */
28 #define DEBUG 0x0001
29 
30 #define DEBUG_PRINT_L1(...)	debug_print(DEBUG_LEVEL_1_BIT, __VA_ARGS__)
31 #define DEBUG_PRINT_L2(...)	debug_print(DEBUG_LEVEL_2_BIT, __VA_ARGS__)
32 #define DEBUG_PRINT_L3(...)	debug_print(DEBUG_LEVEL_3_BIT, __VA_ARGS__)
33 #define DEBUG_PRINT_L4(...)	debug_print(DEBUG_LEVEL_4_BIT, __VA_ARGS__)
34 #define DEBUG_PRINT_T(...)	debug_print(DEBUG_TIMING_BIT, __VA_ARGS__)
35 
36 static void debug_print(int level, const char *s, ...)
37 {
38 	va_list args;
39 
40 	va_start(args, s);
41 
42 	if (DEBUG & level)
43 		vfprintf(stdout, s, args);
44 	va_end(args);
45 }
46 
47 #ifndef min
48 #define min(x, y) ((x) < (y) ? x : y)
49 #endif
50 
51 #define RETURN_FROM_TEST(_ret) \
52 	do { \
53 		DEBUG_PRINT_L1( \
54 			"\tTest %s returned %d\n", __func__, _ret); \
55 		return _ret; \
56 	} while (0)
57 
58 #define ADI_BLKSZ	64
59 #define ADI_MAX_VERSION	15
60 
61 #define TEST_STEP_FAILURE(_ret) \
62 	do { \
63 		fprintf(stderr, "\tTest step failure: %d at %s:%d\n", \
64 			_ret, __func__, __LINE__); \
65 		goto out; \
66 	} while (0)
67 
68 #define RDTICK(_x) \
69 	asm volatile(" rd %%tick, %0\n" : "=r" (_x))
70 
71 static int random_version(void)
72 {
73 	long tick;
74 
75 	RDTICK(tick);
76 
77 	return tick % (ADI_MAX_VERSION + 1);
78 }
79 
80 #define MAX_RANGES_SUPPORTED	5
81 static const char system_ram_str[] = "System RAM\n";
82 static int range_count;
83 static unsigned long long int start_addr[MAX_RANGES_SUPPORTED];
84 static unsigned long long int   end_addr[MAX_RANGES_SUPPORTED];
85 
86 struct stats {
87 	char		name[16];
88 	unsigned long	total;
89 	unsigned long	count;
90 	unsigned long	bytes;
91 };
92 
93 static struct stats read_stats = {
94 	.name = "read", .total = 0, .count = 0, .bytes = 0};
95 static struct stats pread_stats = {
96 	.name = "pread", .total = 0, .count = 0, .bytes = 0};
97 static struct stats write_stats = {
98 	.name = "write", .total = 0, .count = 0, .bytes = 0};
99 static struct stats pwrite_stats = {
100 	.name = "pwrite", .total = 0, .count = 0, .bytes = 0};
101 static struct stats seek_stats = {
102 	.name = "seek", .total = 0, .count = 0, .bytes = 0};
103 
104 static void update_stats(struct stats * const ustats,
105 			 unsigned long measurement, unsigned long bytes)
106 {
107 	ustats->total += measurement;
108 	ustats->bytes += bytes;
109 	ustats->count++;
110 }
111 
112 static void print_ustats(const struct stats * const ustats)
113 {
114 	DEBUG_PRINT_L1("%s\t%7d\t%7.0f\t%7.0f\n",
115 		       ustats->name, ustats->count,
116 		       (float)ustats->total / (float)ustats->count,
117 		       (float)ustats->bytes / (float)ustats->count);
118 }
119 
120 static void print_stats(void)
121 {
122 	DEBUG_PRINT_L1("\nSyscall\tCall\tAvgTime\tAvgSize\n"
123 		       "\tCount\t(ticks)\t(bytes)\n"
124 		       "-------------------------------\n");
125 
126 	print_ustats(&read_stats);
127 	print_ustats(&pread_stats);
128 	print_ustats(&write_stats);
129 	print_ustats(&pwrite_stats);
130 	print_ustats(&seek_stats);
131 }
132 
133 static int build_memory_map(void)
134 {
135 	char line[256];
136 	FILE *fp;
137 	int i;
138 
139 	range_count = 0;
140 
141 	fp = fopen("/proc/iomem", "r");
142 	if (!fp) {
143 		fprintf(stderr, "/proc/iomem: error %d: %s\n",
144 			errno, strerror(errno));
145 		return -errno;
146 	}
147 
148 	while (fgets(line, sizeof(line), fp) != 0) {
149 		if (strstr(line, system_ram_str)) {
150 			char *dash, *end_ptr;
151 
152 			/* Given a line like this:
153 			 * d0400000-10ffaffff : System RAM
154 			 * replace the "-" with a space
155 			 */
156 			dash = strstr(line, "-");
157 			dash[0] = 0x20;
158 
159 			start_addr[range_count] = strtoull(line, &end_ptr, 16);
160 			end_addr[range_count] = strtoull(end_ptr, NULL, 16);
161 			range_count++;
162 		}
163 	}
164 
165 	fclose(fp);
166 
167 	DEBUG_PRINT_L1("RAM Ranges\n");
168 	for (i = 0; i < range_count; i++)
169 		DEBUG_PRINT_L1("\trange %d: 0x%llx\t- 0x%llx\n",
170 			       i, start_addr[i], end_addr[i]);
171 
172 	if (range_count == 0) {
173 		fprintf(stderr, "No valid address ranges found.  Error.\n");
174 		return -1;
175 	}
176 
177 	return 0;
178 }
179 
180 static int read_adi(int fd, unsigned char *buf, int buf_sz)
181 {
182 	int ret, bytes_read = 0;
183 	long start, end, elapsed_time = 0;
184 
185 	do {
186 		RDTICK(start);
187 		ret = read(fd, buf + bytes_read, buf_sz - bytes_read);
188 		RDTICK(end);
189 		if (ret < 0)
190 			return -errno;
191 
192 		elapsed_time += end - start;
193 		update_stats(&read_stats, elapsed_time, buf_sz);
194 		bytes_read += ret;
195 
196 	} while (bytes_read < buf_sz);
197 
198 	DEBUG_PRINT_T("\tread elapsed timed = %ld\n", elapsed_time);
199 	DEBUG_PRINT_L3("\tRead  %d bytes\n", bytes_read);
200 
201 	return bytes_read;
202 }
203 
204 static int pread_adi(int fd, unsigned char *buf,
205 		     int buf_sz, unsigned long offset)
206 {
207 	int ret, i, bytes_read = 0;
208 	unsigned long cur_offset;
209 	long start, end, elapsed_time = 0;
210 
211 	cur_offset = offset;
212 	do {
213 		RDTICK(start);
214 		ret = pread(fd, buf + bytes_read, buf_sz - bytes_read,
215 			    cur_offset);
216 		RDTICK(end);
217 		if (ret < 0)
218 			return -errno;
219 
220 		elapsed_time += end - start;
221 		update_stats(&pread_stats, elapsed_time, buf_sz);
222 		bytes_read += ret;
223 		cur_offset += ret;
224 
225 	} while (bytes_read < buf_sz);
226 
227 	DEBUG_PRINT_T("\tpread elapsed timed = %ld\n", elapsed_time);
228 	DEBUG_PRINT_L3("\tRead  %d bytes starting at offset 0x%lx\n",
229 		       bytes_read, offset);
230 	for (i = 0; i < bytes_read; i++)
231 		DEBUG_PRINT_L4("\t\t0x%lx\t%d\n", offset + i, buf[i]);
232 
233 	return bytes_read;
234 }
235 
236 static int write_adi(int fd, const unsigned char * const buf, int buf_sz)
237 {
238 	int ret, bytes_written = 0;
239 	long start, end, elapsed_time = 0;
240 
241 	do {
242 		RDTICK(start);
243 		ret = write(fd, buf + bytes_written, buf_sz - bytes_written);
244 		RDTICK(end);
245 		if (ret < 0)
246 			return -errno;
247 
248 		elapsed_time += (end - start);
249 		update_stats(&write_stats, elapsed_time, buf_sz);
250 		bytes_written += ret;
251 	} while (bytes_written < buf_sz);
252 
253 	DEBUG_PRINT_T("\twrite elapsed timed = %ld\n", elapsed_time);
254 	DEBUG_PRINT_L3("\tWrote %d of %d bytes\n", bytes_written, buf_sz);
255 
256 	return bytes_written;
257 }
258 
259 static int pwrite_adi(int fd, const unsigned char * const buf,
260 		      int buf_sz, unsigned long offset)
261 {
262 	int ret, bytes_written = 0;
263 	unsigned long cur_offset;
264 	long start, end, elapsed_time = 0;
265 
266 	cur_offset = offset;
267 
268 	do {
269 		RDTICK(start);
270 		ret = pwrite(fd, buf + bytes_written,
271 			     buf_sz - bytes_written, cur_offset);
272 		RDTICK(end);
273 		if (ret < 0) {
274 			fprintf(stderr, "pwrite(): error %d: %s\n",
275 				errno, strerror(errno));
276 			return -errno;
277 		}
278 
279 		elapsed_time += (end - start);
280 		update_stats(&pwrite_stats, elapsed_time, buf_sz);
281 		bytes_written += ret;
282 		cur_offset += ret;
283 
284 	} while (bytes_written < buf_sz);
285 
286 	DEBUG_PRINT_T("\tpwrite elapsed timed = %ld\n", elapsed_time);
287 	DEBUG_PRINT_L3("\tWrote %d of %d bytes starting at address 0x%lx\n",
288 		       bytes_written, buf_sz, offset);
289 
290 	return bytes_written;
291 }
292 
293 static off_t seek_adi(int fd, off_t offset, int whence)
294 {
295 	long start, end;
296 	off_t ret;
297 
298 	RDTICK(start);
299 	ret = lseek(fd, offset, whence);
300 	RDTICK(end);
301 	DEBUG_PRINT_L2("\tlseek ret = 0x%llx\n", ret);
302 	if (ret < 0)
303 		goto out;
304 
305 	DEBUG_PRINT_T("\tlseek elapsed timed = %ld\n", end - start);
306 	update_stats(&seek_stats, end - start, 0);
307 
308 out:
309 	(void)lseek(fd, 0, SEEK_END);
310 	return ret;
311 }
312 
313 static int test0_prpw_aligned_1byte(int fd)
314 {
315 	/* somewhat arbitrarily chosen address */
316 	unsigned long paddr =
317 		(end_addr[range_count - 1] - 0x1000) & ~(ADI_BLKSZ - 1);
318 	unsigned char version[1], expected_version;
319 	loff_t offset;
320 	int ret;
321 
322 	version[0] = random_version();
323 	expected_version = version[0];
324 
325 	offset = paddr / ADI_BLKSZ;
326 
327 	ret = pwrite_adi(fd, version, sizeof(version), offset);
328 	if (ret != sizeof(version))
329 		TEST_STEP_FAILURE(ret);
330 
331 	ret = pread_adi(fd, version, sizeof(version), offset);
332 	if (ret != sizeof(version))
333 		TEST_STEP_FAILURE(ret);
334 
335 	if (expected_version != version[0]) {
336 		DEBUG_PRINT_L2("\tExpected version %d but read version %d\n",
337 			       expected_version, version[0]);
338 		TEST_STEP_FAILURE(-expected_version);
339 	}
340 
341 	ret = 0;
342 out:
343 	RETURN_FROM_TEST(ret);
344 }
345 
346 #define TEST1_VERSION_SZ	4096
347 static int test1_prpw_aligned_4096bytes(int fd)
348 {
349 	/* somewhat arbitrarily chosen address */
350 	unsigned long paddr =
351 		(end_addr[range_count - 1] - 0x6000) & ~(ADI_BLKSZ - 1);
352 	unsigned char version[TEST1_VERSION_SZ],
353 		expected_version[TEST1_VERSION_SZ];
354 	loff_t offset;
355 	int ret, i;
356 
357 	for (i = 0; i < TEST1_VERSION_SZ; i++) {
358 		version[i] = random_version();
359 		expected_version[i] = version[i];
360 	}
361 
362 	offset = paddr / ADI_BLKSZ;
363 
364 	ret = pwrite_adi(fd, version, sizeof(version), offset);
365 	if (ret != sizeof(version))
366 		TEST_STEP_FAILURE(ret);
367 
368 	ret = pread_adi(fd, version, sizeof(version), offset);
369 	if (ret != sizeof(version))
370 		TEST_STEP_FAILURE(ret);
371 
372 	for (i = 0; i < TEST1_VERSION_SZ; i++) {
373 		if (expected_version[i] != version[i]) {
374 			DEBUG_PRINT_L2(
375 				"\tExpected version %d but read version %d\n",
376 				expected_version, version[0]);
377 			TEST_STEP_FAILURE(-expected_version[i]);
378 		}
379 	}
380 
381 	ret = 0;
382 out:
383 	RETURN_FROM_TEST(ret);
384 }
385 
386 #define TEST2_VERSION_SZ	10327
387 static int test2_prpw_aligned_10327bytes(int fd)
388 {
389 	/* somewhat arbitrarily chosen address */
390 	unsigned long paddr =
391 		(start_addr[0] + 0x6000) & ~(ADI_BLKSZ - 1);
392 	unsigned char version[TEST2_VERSION_SZ],
393 		expected_version[TEST2_VERSION_SZ];
394 	loff_t offset;
395 	int ret, i;
396 
397 	for (i = 0; i < TEST2_VERSION_SZ; i++) {
398 		version[i] = random_version();
399 		expected_version[i] = version[i];
400 	}
401 
402 	offset = paddr / ADI_BLKSZ;
403 
404 	ret = pwrite_adi(fd, version, sizeof(version), offset);
405 	if (ret != sizeof(version))
406 		TEST_STEP_FAILURE(ret);
407 
408 	ret = pread_adi(fd, version, sizeof(version), offset);
409 	if (ret != sizeof(version))
410 		TEST_STEP_FAILURE(ret);
411 
412 	for (i = 0; i < TEST2_VERSION_SZ; i++) {
413 		if (expected_version[i] != version[i]) {
414 			DEBUG_PRINT_L2(
415 				"\tExpected version %d but read version %d\n",
416 				expected_version, version[0]);
417 			TEST_STEP_FAILURE(-expected_version[i]);
418 		}
419 	}
420 
421 	ret = 0;
422 out:
423 	RETURN_FROM_TEST(ret);
424 }
425 
426 #define TEST3_VERSION_SZ	12541
427 static int test3_prpw_unaligned_12541bytes(int fd)
428 {
429 	/* somewhat arbitrarily chosen address */
430 	unsigned long paddr =
431 		((start_addr[0] + 0xC000) & ~(ADI_BLKSZ - 1)) + 17;
432 	unsigned char version[TEST3_VERSION_SZ],
433 		expected_version[TEST3_VERSION_SZ];
434 	loff_t offset;
435 	int ret, i;
436 
437 	for (i = 0; i < TEST3_VERSION_SZ; i++) {
438 		version[i] = random_version();
439 		expected_version[i] = version[i];
440 	}
441 
442 	offset = paddr / ADI_BLKSZ;
443 
444 	ret = pwrite_adi(fd, version, sizeof(version), offset);
445 	if (ret != sizeof(version))
446 		TEST_STEP_FAILURE(ret);
447 
448 	ret = pread_adi(fd, version, sizeof(version), offset);
449 	if (ret != sizeof(version))
450 		TEST_STEP_FAILURE(ret);
451 
452 	for (i = 0; i < TEST3_VERSION_SZ; i++) {
453 		if (expected_version[i] != version[i]) {
454 			DEBUG_PRINT_L2(
455 				"\tExpected version %d but read version %d\n",
456 				expected_version, version[0]);
457 			TEST_STEP_FAILURE(-expected_version[i]);
458 		}
459 	}
460 
461 	ret = 0;
462 out:
463 	RETURN_FROM_TEST(ret);
464 }
465 
466 static int test4_lseek(int fd)
467 {
468 #define	OFFSET_ADD	(0x100)
469 #define OFFSET_SUBTRACT	(0xFFFFFFF000000000)
470 
471 	off_t offset_out, offset_in;
472 	int ret;
473 
474 
475 	offset_in = 0x123456789abcdef0;
476 	offset_out = seek_adi(fd, offset_in, SEEK_SET);
477 	if (offset_out != offset_in) {
478 		ret = -1;
479 		TEST_STEP_FAILURE(ret);
480 	}
481 
482 	/* seek to the current offset.  this should return EINVAL */
483 	offset_out = seek_adi(fd, offset_in, SEEK_SET);
484 	if (offset_out < 0 && errno == EINVAL)
485 		DEBUG_PRINT_L2(
486 			"\tSEEK_SET failed as designed. Not an error\n");
487 	else {
488 		ret = -2;
489 		TEST_STEP_FAILURE(ret);
490 	}
491 
492 	offset_out = seek_adi(fd, 0, SEEK_CUR);
493 	if (offset_out != offset_in) {
494 		ret = -3;
495 		TEST_STEP_FAILURE(ret);
496 	}
497 
498 	offset_out = seek_adi(fd, OFFSET_ADD, SEEK_CUR);
499 	if (offset_out != (offset_in + OFFSET_ADD)) {
500 		ret = -4;
501 		TEST_STEP_FAILURE(ret);
502 	}
503 
504 	offset_out = seek_adi(fd, OFFSET_SUBTRACT, SEEK_CUR);
505 	if (offset_out != (offset_in + OFFSET_ADD + OFFSET_SUBTRACT)) {
506 		ret = -5;
507 		TEST_STEP_FAILURE(ret);
508 	}
509 
510 	ret = 0;
511 out:
512 	RETURN_FROM_TEST(ret);
513 }
514 
515 static int test5_rw_aligned_1byte(int fd)
516 {
517 	/* somewhat arbitrarily chosen address */
518 	unsigned long paddr =
519 		(end_addr[range_count - 1] - 0xF000) & ~(ADI_BLKSZ - 1);
520 	unsigned char version, expected_version;
521 	loff_t offset;
522 	off_t oret;
523 	int ret;
524 
525 	offset = paddr / ADI_BLKSZ;
526 	version = expected_version = random_version();
527 
528 	oret = seek_adi(fd, offset, SEEK_SET);
529 	if (oret != offset) {
530 		ret = -1;
531 		TEST_STEP_FAILURE(ret);
532 	}
533 
534 	ret = write_adi(fd, &version, sizeof(version));
535 	if (ret != sizeof(version))
536 		TEST_STEP_FAILURE(ret);
537 
538 	oret = seek_adi(fd, offset, SEEK_SET);
539 	if (oret != offset) {
540 		ret = -1;
541 		TEST_STEP_FAILURE(ret);
542 	}
543 
544 	ret = read_adi(fd, &version, sizeof(version));
545 	if (ret != sizeof(version))
546 		TEST_STEP_FAILURE(ret);
547 
548 	if (expected_version != version) {
549 		DEBUG_PRINT_L2("\tExpected version %d but read version %d\n",
550 			       expected_version, version);
551 		TEST_STEP_FAILURE(-expected_version);
552 	}
553 
554 	ret = 0;
555 out:
556 	RETURN_FROM_TEST(ret);
557 }
558 
559 #define TEST6_VERSION_SZ        9434
560 static int test6_rw_aligned_9434bytes(int fd)
561 {
562 	/* somewhat arbitrarily chosen address */
563 	unsigned long paddr =
564 		(end_addr[range_count - 1] - 0x5F000) & ~(ADI_BLKSZ - 1);
565 	unsigned char version[TEST6_VERSION_SZ],
566 		      expected_version[TEST6_VERSION_SZ];
567 	loff_t offset;
568 	off_t oret;
569 	int ret, i;
570 
571 	offset = paddr / ADI_BLKSZ;
572 	for (i = 0; i < TEST6_VERSION_SZ; i++)
573 		version[i] = expected_version[i] = random_version();
574 
575 	oret = seek_adi(fd, offset, SEEK_SET);
576 	if (oret != offset) {
577 		ret = -1;
578 		TEST_STEP_FAILURE(ret);
579 	}
580 
581 	ret = write_adi(fd, version, sizeof(version));
582 	if (ret != sizeof(version))
583 		TEST_STEP_FAILURE(ret);
584 
585 	memset(version, 0, TEST6_VERSION_SZ);
586 
587 	oret = seek_adi(fd, offset, SEEK_SET);
588 	if (oret != offset) {
589 		ret = -1;
590 		TEST_STEP_FAILURE(ret);
591 	}
592 
593 	ret = read_adi(fd, version, sizeof(version));
594 	if (ret != sizeof(version))
595 		TEST_STEP_FAILURE(ret);
596 
597 	for (i = 0; i < TEST6_VERSION_SZ; i++) {
598 		if (expected_version[i] != version[i]) {
599 			DEBUG_PRINT_L2(
600 				"\tExpected version %d but read version %d\n",
601 				expected_version[i], version[i]);
602 			TEST_STEP_FAILURE(-expected_version[i]);
603 		}
604 	}
605 
606 	ret = 0;
607 out:
608 	RETURN_FROM_TEST(ret);
609 }
610 
611 #define TEST7_VERSION_SZ        14963
612 static int test7_rw_aligned_14963bytes(int fd)
613 {
614 	/* somewhat arbitrarily chosen address */
615 	unsigned long paddr =
616 	  ((start_addr[range_count - 1] + 0xF000) & ~(ADI_BLKSZ - 1)) + 39;
617 	unsigned char version[TEST7_VERSION_SZ],
618 		      expected_version[TEST7_VERSION_SZ];
619 	loff_t offset;
620 	off_t oret;
621 	int ret, i;
622 
623 	offset = paddr / ADI_BLKSZ;
624 	for (i = 0; i < TEST7_VERSION_SZ; i++) {
625 		version[i] = random_version();
626 		expected_version[i] = version[i];
627 	}
628 
629 	oret = seek_adi(fd, offset, SEEK_SET);
630 	if (oret != offset) {
631 		ret = -1;
632 		TEST_STEP_FAILURE(ret);
633 	}
634 
635 	ret = write_adi(fd, version, sizeof(version));
636 	if (ret != sizeof(version))
637 		TEST_STEP_FAILURE(ret);
638 
639 	memset(version, 0, TEST7_VERSION_SZ);
640 
641 	oret = seek_adi(fd, offset, SEEK_SET);
642 	if (oret != offset) {
643 		ret = -1;
644 		TEST_STEP_FAILURE(ret);
645 	}
646 
647 	ret = read_adi(fd, version, sizeof(version));
648 	if (ret != sizeof(version))
649 		TEST_STEP_FAILURE(ret);
650 
651 	for (i = 0; i < TEST7_VERSION_SZ; i++) {
652 		if (expected_version[i] != version[i]) {
653 			DEBUG_PRINT_L2(
654 				"\tExpected version %d but read version %d\n",
655 				expected_version[i], version[i]);
656 			TEST_STEP_FAILURE(-expected_version[i]);
657 		}
658 
659 		paddr += ADI_BLKSZ;
660 	}
661 
662 	ret = 0;
663 out:
664 	RETURN_FROM_TEST(ret);
665 }
666 
667 static int (*tests[])(int fd) = {
668 	test0_prpw_aligned_1byte,
669 	test1_prpw_aligned_4096bytes,
670 	test2_prpw_aligned_10327bytes,
671 	test3_prpw_unaligned_12541bytes,
672 	test4_lseek,
673 	test5_rw_aligned_1byte,
674 	test6_rw_aligned_9434bytes,
675 	test7_rw_aligned_14963bytes,
676 };
677 #define TEST_COUNT	ARRAY_SIZE(tests)
678 
679 int main(int argc, char *argv[])
680 {
681 	int fd, ret, test;
682 
683 	ret = build_memory_map();
684 	if (ret < 0)
685 		return ret;
686 
687 	fd = open("/dev/adi", O_RDWR);
688 	if (fd < 0) {
689 		fprintf(stderr, "open: error %d: %s\n",
690 			errno, strerror(errno));
691 		return -errno;
692 	}
693 
694 	for (test = 0; test < TEST_COUNT; test++) {
695 		DEBUG_PRINT_L1("Running test #%d\n", test);
696 
697 		ret = (*tests[test])(fd);
698 		if (ret != 0)
699 			ksft_test_result_fail("Test #%d failed: error %d\n",
700 					      test, ret);
701 		else
702 			ksft_test_result_pass("Test #%d passed\n", test);
703 	}
704 
705 	print_stats();
706 	close(fd);
707 
708 	if (ksft_get_fail_cnt() > 0)
709 		ksft_exit_fail();
710 	else
711 		ksft_exit_pass();
712 
713 	/* it's impossible to get here, but the compiler throws a warning
714 	 * about control reaching the end of non-void function.  bah.
715 	 */
716 	return 0;
717 }
718