1 // SPDX-License-Identifier: GPL-2.0
3 * selftest for sparc64's privileged ADI driver
5 * Author: Tom Hromatka <tom.hromatka@oracle.com>
7 #include <linux/kernel.h>
14 #include <sys/syscall.h>
15 #include <sys/types.h>
19 #include "../../kselftest.h"
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)
28 # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
31 /* bit mask of enabled bits to print */
34 #define DEBUG_PRINT_L1(...) debug_print(DEBUG_LEVEL_1_BIT, __VA_ARGS__)
35 #define DEBUG_PRINT_L2(...) debug_print(DEBUG_LEVEL_2_BIT, __VA_ARGS__)
36 #define DEBUG_PRINT_L3(...) debug_print(DEBUG_LEVEL_3_BIT, __VA_ARGS__)
37 #define DEBUG_PRINT_L4(...) debug_print(DEBUG_LEVEL_4_BIT, __VA_ARGS__)
38 #define DEBUG_PRINT_T(...) debug_print(DEBUG_TIMING_BIT, __VA_ARGS__)
40 static void debug_print(int level
, const char *s
, ...)
47 vfprintf(stdout
, s
, args
);
52 #define min(x, y) ((x) < (y) ? x : y)
55 #define RETURN_FROM_TEST(_ret) \
58 "\tTest %s returned %d\n", __func__, _ret); \
63 #define ADI_MAX_VERSION 15
65 #define TEST_STEP_FAILURE(_ret) \
67 fprintf(stderr, "\tTest step failure: %d at %s:%d\n", \
68 _ret, __func__, __LINE__); \
73 asm volatile(" rd %%tick, %0\n" : "=r" (_x))
75 static int random_version(void)
81 return tick
% (ADI_MAX_VERSION
+ 1);
84 #define MAX_RANGES_SUPPORTED 5
85 static const char system_ram_str
[] = "System RAM\n";
86 static int range_count
;
87 static unsigned long long int start_addr
[MAX_RANGES_SUPPORTED
];
88 static unsigned long long int end_addr
[MAX_RANGES_SUPPORTED
];
97 static struct stats read_stats
= {
98 .name
= "read", .total
= 0, .count
= 0, .bytes
= 0};
99 static struct stats pread_stats
= {
100 .name
= "pread", .total
= 0, .count
= 0, .bytes
= 0};
101 static struct stats write_stats
= {
102 .name
= "write", .total
= 0, .count
= 0, .bytes
= 0};
103 static struct stats pwrite_stats
= {
104 .name
= "pwrite", .total
= 0, .count
= 0, .bytes
= 0};
105 static struct stats seek_stats
= {
106 .name
= "seek", .total
= 0, .count
= 0, .bytes
= 0};
108 static void update_stats(struct stats
* const ustats
,
109 unsigned long measurement
, unsigned long bytes
)
111 ustats
->total
+= measurement
;
112 ustats
->bytes
+= bytes
;
116 static void print_ustats(const struct stats
* const ustats
)
118 DEBUG_PRINT_L1("%s\t%7d\t%7.0f\t%7.0f\n",
119 ustats
->name
, ustats
->count
,
120 (float)ustats
->total
/ (float)ustats
->count
,
121 (float)ustats
->bytes
/ (float)ustats
->count
);
124 static void print_stats(void)
126 DEBUG_PRINT_L1("\nSyscall\tCall\tAvgTime\tAvgSize\n"
127 "\tCount\t(ticks)\t(bytes)\n"
128 "-------------------------------\n");
130 print_ustats(&read_stats
);
131 print_ustats(&pread_stats
);
132 print_ustats(&write_stats
);
133 print_ustats(&pwrite_stats
);
134 print_ustats(&seek_stats
);
137 static int build_memory_map(void)
145 fp
= fopen("/proc/iomem", "r");
147 fprintf(stderr
, "/proc/iomem: error %d: %s\n",
148 errno
, strerror(errno
));
152 while (fgets(line
, sizeof(line
), fp
) != 0) {
153 if (strstr(line
, system_ram_str
)) {
154 char *dash
, *end_ptr
;
156 /* Given a line like this:
157 * d0400000-10ffaffff : System RAM
158 * replace the "-" with a space
160 dash
= strstr(line
, "-");
163 start_addr
[range_count
] = strtoull(line
, &end_ptr
, 16);
164 end_addr
[range_count
] = strtoull(end_ptr
, NULL
, 16);
171 DEBUG_PRINT_L1("RAM Ranges\n");
172 for (i
= 0; i
< range_count
; i
++)
173 DEBUG_PRINT_L1("\trange %d: 0x%llx\t- 0x%llx\n",
174 i
, start_addr
[i
], end_addr
[i
]);
176 if (range_count
== 0) {
177 fprintf(stderr
, "No valid address ranges found. Error.\n");
184 static int read_adi(int fd
, unsigned char *buf
, int buf_sz
)
186 int ret
, bytes_read
= 0;
187 long start
, end
, elapsed_time
= 0;
191 ret
= read(fd
, buf
+ bytes_read
, buf_sz
- bytes_read
);
196 elapsed_time
+= end
- start
;
197 update_stats(&read_stats
, elapsed_time
, buf_sz
);
200 } while (bytes_read
< buf_sz
);
202 DEBUG_PRINT_T("\tread elapsed timed = %ld\n", elapsed_time
);
203 DEBUG_PRINT_L3("\tRead %d bytes\n", bytes_read
);
208 static int pread_adi(int fd
, unsigned char *buf
,
209 int buf_sz
, unsigned long offset
)
211 int ret
, i
, bytes_read
= 0;
212 unsigned long cur_offset
;
213 long start
, end
, elapsed_time
= 0;
218 ret
= pread(fd
, buf
+ bytes_read
, buf_sz
- bytes_read
,
224 elapsed_time
+= end
- start
;
225 update_stats(&pread_stats
, elapsed_time
, buf_sz
);
229 } while (bytes_read
< buf_sz
);
231 DEBUG_PRINT_T("\tpread elapsed timed = %ld\n", elapsed_time
);
232 DEBUG_PRINT_L3("\tRead %d bytes starting at offset 0x%lx\n",
234 for (i
= 0; i
< bytes_read
; i
++)
235 DEBUG_PRINT_L4("\t\t0x%lx\t%d\n", offset
+ i
, buf
[i
]);
240 static int write_adi(int fd
, const unsigned char * const buf
, int buf_sz
)
242 int ret
, bytes_written
= 0;
243 long start
, end
, elapsed_time
= 0;
247 ret
= write(fd
, buf
+ bytes_written
, buf_sz
- bytes_written
);
252 elapsed_time
+= (end
- start
);
253 update_stats(&write_stats
, elapsed_time
, buf_sz
);
254 bytes_written
+= ret
;
255 } while (bytes_written
< buf_sz
);
257 DEBUG_PRINT_T("\twrite elapsed timed = %ld\n", elapsed_time
);
258 DEBUG_PRINT_L3("\tWrote %d of %d bytes\n", bytes_written
, buf_sz
);
260 return bytes_written
;
263 static int pwrite_adi(int fd
, const unsigned char * const buf
,
264 int buf_sz
, unsigned long offset
)
266 int ret
, bytes_written
= 0;
267 unsigned long cur_offset
;
268 long start
, end
, elapsed_time
= 0;
274 ret
= pwrite(fd
, buf
+ bytes_written
,
275 buf_sz
- bytes_written
, cur_offset
);
278 fprintf(stderr
, "pwrite(): error %d: %s\n",
279 errno
, strerror(errno
));
283 elapsed_time
+= (end
- start
);
284 update_stats(&pwrite_stats
, elapsed_time
, buf_sz
);
285 bytes_written
+= ret
;
288 } while (bytes_written
< buf_sz
);
290 DEBUG_PRINT_T("\tpwrite elapsed timed = %ld\n", elapsed_time
);
291 DEBUG_PRINT_L3("\tWrote %d of %d bytes starting at address 0x%lx\n",
292 bytes_written
, buf_sz
, offset
);
294 return bytes_written
;
297 static off_t
seek_adi(int fd
, off_t offset
, int whence
)
303 ret
= lseek(fd
, offset
, whence
);
305 DEBUG_PRINT_L2("\tlseek ret = 0x%llx\n", ret
);
309 DEBUG_PRINT_T("\tlseek elapsed timed = %ld\n", end
- start
);
310 update_stats(&seek_stats
, end
- start
, 0);
313 (void)lseek(fd
, 0, SEEK_END
);
317 static int test0_prpw_aligned_1byte(int fd
)
319 /* somewhat arbitrarily chosen address */
320 unsigned long paddr
=
321 (end_addr
[range_count
- 1] - 0x1000) & ~(ADI_BLKSZ
- 1);
322 unsigned char version
[1], expected_version
;
326 version
[0] = random_version();
327 expected_version
= version
[0];
329 offset
= paddr
/ ADI_BLKSZ
;
331 ret
= pwrite_adi(fd
, version
, sizeof(version
), offset
);
332 if (ret
!= sizeof(version
))
333 TEST_STEP_FAILURE(ret
);
335 ret
= pread_adi(fd
, version
, sizeof(version
), offset
);
336 if (ret
!= sizeof(version
))
337 TEST_STEP_FAILURE(ret
);
339 if (expected_version
!= version
[0]) {
340 DEBUG_PRINT_L2("\tExpected version %d but read version %d\n",
341 expected_version
, version
[0]);
342 TEST_STEP_FAILURE(-expected_version
);
347 RETURN_FROM_TEST(ret
);
350 #define TEST1_VERSION_SZ 4096
351 static int test1_prpw_aligned_4096bytes(int fd
)
353 /* somewhat arbitrarily chosen address */
354 unsigned long paddr
=
355 (end_addr
[range_count
- 1] - 0x6000) & ~(ADI_BLKSZ
- 1);
356 unsigned char version
[TEST1_VERSION_SZ
],
357 expected_version
[TEST1_VERSION_SZ
];
361 for (i
= 0; i
< TEST1_VERSION_SZ
; i
++) {
362 version
[i
] = random_version();
363 expected_version
[i
] = version
[i
];
366 offset
= paddr
/ ADI_BLKSZ
;
368 ret
= pwrite_adi(fd
, version
, sizeof(version
), offset
);
369 if (ret
!= sizeof(version
))
370 TEST_STEP_FAILURE(ret
);
372 ret
= pread_adi(fd
, version
, sizeof(version
), offset
);
373 if (ret
!= sizeof(version
))
374 TEST_STEP_FAILURE(ret
);
376 for (i
= 0; i
< TEST1_VERSION_SZ
; i
++) {
377 if (expected_version
[i
] != version
[i
]) {
379 "\tExpected version %d but read version %d\n",
380 expected_version
, version
[0]);
381 TEST_STEP_FAILURE(-expected_version
[i
]);
387 RETURN_FROM_TEST(ret
);
390 #define TEST2_VERSION_SZ 10327
391 static int test2_prpw_aligned_10327bytes(int fd
)
393 /* somewhat arbitrarily chosen address */
394 unsigned long paddr
=
395 (start_addr
[0] + 0x6000) & ~(ADI_BLKSZ
- 1);
396 unsigned char version
[TEST2_VERSION_SZ
],
397 expected_version
[TEST2_VERSION_SZ
];
401 for (i
= 0; i
< TEST2_VERSION_SZ
; i
++) {
402 version
[i
] = random_version();
403 expected_version
[i
] = version
[i
];
406 offset
= paddr
/ ADI_BLKSZ
;
408 ret
= pwrite_adi(fd
, version
, sizeof(version
), offset
);
409 if (ret
!= sizeof(version
))
410 TEST_STEP_FAILURE(ret
);
412 ret
= pread_adi(fd
, version
, sizeof(version
), offset
);
413 if (ret
!= sizeof(version
))
414 TEST_STEP_FAILURE(ret
);
416 for (i
= 0; i
< TEST2_VERSION_SZ
; i
++) {
417 if (expected_version
[i
] != version
[i
]) {
419 "\tExpected version %d but read version %d\n",
420 expected_version
, version
[0]);
421 TEST_STEP_FAILURE(-expected_version
[i
]);
427 RETURN_FROM_TEST(ret
);
430 #define TEST3_VERSION_SZ 12541
431 static int test3_prpw_unaligned_12541bytes(int fd
)
433 /* somewhat arbitrarily chosen address */
434 unsigned long paddr
=
435 ((start_addr
[0] + 0xC000) & ~(ADI_BLKSZ
- 1)) + 17;
436 unsigned char version
[TEST3_VERSION_SZ
],
437 expected_version
[TEST3_VERSION_SZ
];
441 for (i
= 0; i
< TEST3_VERSION_SZ
; i
++) {
442 version
[i
] = random_version();
443 expected_version
[i
] = version
[i
];
446 offset
= paddr
/ ADI_BLKSZ
;
448 ret
= pwrite_adi(fd
, version
, sizeof(version
), offset
);
449 if (ret
!= sizeof(version
))
450 TEST_STEP_FAILURE(ret
);
452 ret
= pread_adi(fd
, version
, sizeof(version
), offset
);
453 if (ret
!= sizeof(version
))
454 TEST_STEP_FAILURE(ret
);
456 for (i
= 0; i
< TEST3_VERSION_SZ
; i
++) {
457 if (expected_version
[i
] != version
[i
]) {
459 "\tExpected version %d but read version %d\n",
460 expected_version
, version
[0]);
461 TEST_STEP_FAILURE(-expected_version
[i
]);
467 RETURN_FROM_TEST(ret
);
470 static int test4_lseek(int fd
)
472 #define OFFSET_ADD (0x100)
473 #define OFFSET_SUBTRACT (0xFFFFFFF000000000)
475 off_t offset_out
, offset_in
;
479 offset_in
= 0x123456789abcdef0;
480 offset_out
= seek_adi(fd
, offset_in
, SEEK_SET
);
481 if (offset_out
!= offset_in
) {
483 TEST_STEP_FAILURE(ret
);
486 /* seek to the current offset. this should return EINVAL */
487 offset_out
= seek_adi(fd
, offset_in
, SEEK_SET
);
488 if (offset_out
< 0 && errno
== EINVAL
)
490 "\tSEEK_SET failed as designed. Not an error\n");
493 TEST_STEP_FAILURE(ret
);
496 offset_out
= seek_adi(fd
, 0, SEEK_CUR
);
497 if (offset_out
!= offset_in
) {
499 TEST_STEP_FAILURE(ret
);
502 offset_out
= seek_adi(fd
, OFFSET_ADD
, SEEK_CUR
);
503 if (offset_out
!= (offset_in
+ OFFSET_ADD
)) {
505 TEST_STEP_FAILURE(ret
);
508 offset_out
= seek_adi(fd
, OFFSET_SUBTRACT
, SEEK_CUR
);
509 if (offset_out
!= (offset_in
+ OFFSET_ADD
+ OFFSET_SUBTRACT
)) {
511 TEST_STEP_FAILURE(ret
);
516 RETURN_FROM_TEST(ret
);
519 static int test5_rw_aligned_1byte(int fd
)
521 /* somewhat arbitrarily chosen address */
522 unsigned long paddr
=
523 (end_addr
[range_count
- 1] - 0xF000) & ~(ADI_BLKSZ
- 1);
524 unsigned char version
, expected_version
;
529 offset
= paddr
/ ADI_BLKSZ
;
530 version
= expected_version
= random_version();
532 oret
= seek_adi(fd
, offset
, SEEK_SET
);
533 if (oret
!= offset
) {
535 TEST_STEP_FAILURE(ret
);
538 ret
= write_adi(fd
, &version
, sizeof(version
));
539 if (ret
!= sizeof(version
))
540 TEST_STEP_FAILURE(ret
);
542 oret
= seek_adi(fd
, offset
, SEEK_SET
);
543 if (oret
!= offset
) {
545 TEST_STEP_FAILURE(ret
);
548 ret
= read_adi(fd
, &version
, sizeof(version
));
549 if (ret
!= sizeof(version
))
550 TEST_STEP_FAILURE(ret
);
552 if (expected_version
!= version
) {
553 DEBUG_PRINT_L2("\tExpected version %d but read version %d\n",
554 expected_version
, version
);
555 TEST_STEP_FAILURE(-expected_version
);
560 RETURN_FROM_TEST(ret
);
563 #define TEST6_VERSION_SZ 9434
564 static int test6_rw_aligned_9434bytes(int fd
)
566 /* somewhat arbitrarily chosen address */
567 unsigned long paddr
=
568 (end_addr
[range_count
- 1] - 0x5F000) & ~(ADI_BLKSZ
- 1);
569 unsigned char version
[TEST6_VERSION_SZ
],
570 expected_version
[TEST6_VERSION_SZ
];
575 offset
= paddr
/ ADI_BLKSZ
;
576 for (i
= 0; i
< TEST6_VERSION_SZ
; i
++)
577 version
[i
] = expected_version
[i
] = random_version();
579 oret
= seek_adi(fd
, offset
, SEEK_SET
);
580 if (oret
!= offset
) {
582 TEST_STEP_FAILURE(ret
);
585 ret
= write_adi(fd
, version
, sizeof(version
));
586 if (ret
!= sizeof(version
))
587 TEST_STEP_FAILURE(ret
);
589 memset(version
, 0, TEST6_VERSION_SZ
);
591 oret
= seek_adi(fd
, offset
, SEEK_SET
);
592 if (oret
!= offset
) {
594 TEST_STEP_FAILURE(ret
);
597 ret
= read_adi(fd
, version
, sizeof(version
));
598 if (ret
!= sizeof(version
))
599 TEST_STEP_FAILURE(ret
);
601 for (i
= 0; i
< TEST6_VERSION_SZ
; i
++) {
602 if (expected_version
[i
] != version
[i
]) {
604 "\tExpected version %d but read version %d\n",
605 expected_version
[i
], version
[i
]);
606 TEST_STEP_FAILURE(-expected_version
[i
]);
612 RETURN_FROM_TEST(ret
);
615 #define TEST7_VERSION_SZ 14963
616 static int test7_rw_aligned_14963bytes(int fd
)
618 /* somewhat arbitrarily chosen address */
619 unsigned long paddr
=
620 ((start_addr
[range_count
- 1] + 0xF000) & ~(ADI_BLKSZ
- 1)) + 39;
621 unsigned char version
[TEST7_VERSION_SZ
],
622 expected_version
[TEST7_VERSION_SZ
];
627 offset
= paddr
/ ADI_BLKSZ
;
628 for (i
= 0; i
< TEST7_VERSION_SZ
; i
++) {
629 version
[i
] = random_version();
630 expected_version
[i
] = version
[i
];
633 oret
= seek_adi(fd
, offset
, SEEK_SET
);
634 if (oret
!= offset
) {
636 TEST_STEP_FAILURE(ret
);
639 ret
= write_adi(fd
, version
, sizeof(version
));
640 if (ret
!= sizeof(version
))
641 TEST_STEP_FAILURE(ret
);
643 memset(version
, 0, TEST7_VERSION_SZ
);
645 oret
= seek_adi(fd
, offset
, SEEK_SET
);
646 if (oret
!= offset
) {
648 TEST_STEP_FAILURE(ret
);
651 ret
= read_adi(fd
, version
, sizeof(version
));
652 if (ret
!= sizeof(version
))
653 TEST_STEP_FAILURE(ret
);
655 for (i
= 0; i
< TEST7_VERSION_SZ
; i
++) {
656 if (expected_version
[i
] != version
[i
]) {
658 "\tExpected version %d but read version %d\n",
659 expected_version
[i
], version
[i
]);
660 TEST_STEP_FAILURE(-expected_version
[i
]);
668 RETURN_FROM_TEST(ret
);
671 static int (*tests
[])(int fd
) = {
672 test0_prpw_aligned_1byte
,
673 test1_prpw_aligned_4096bytes
,
674 test2_prpw_aligned_10327bytes
,
675 test3_prpw_unaligned_12541bytes
,
677 test5_rw_aligned_1byte
,
678 test6_rw_aligned_9434bytes
,
679 test7_rw_aligned_14963bytes
,
681 #define TEST_COUNT ARRAY_SIZE(tests)
683 int main(int argc
, char *argv
[])
687 ret
= build_memory_map();
691 fd
= open("/dev/adi", O_RDWR
);
693 fprintf(stderr
, "open: error %d: %s\n",
694 errno
, strerror(errno
));
698 for (test
= 0; test
< TEST_COUNT
; test
++) {
699 DEBUG_PRINT_L1("Running test #%d\n", test
);
701 ret
= (*tests
[test
])(fd
);
703 ksft_test_result_fail("Test #%d failed: error %d\n",
706 ksft_test_result_pass("Test #%d passed\n", test
);
712 if (ksft_get_fail_cnt() > 0)
717 /* it's impossible to get here, but the compiler throws a warning
718 * about control reaching the end of non-void function. bah.