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)
27 /* bit mask of enabled bits to print */
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__)
36 static void debug_print(int level
, const char *s
, ...)
43 vfprintf(stdout
, s
, args
);
48 #define min(x, y) ((x) < (y) ? x : y)
51 #define RETURN_FROM_TEST(_ret) \
54 "\tTest %s returned %d\n", __func__, _ret); \
59 #define ADI_MAX_VERSION 15
61 #define TEST_STEP_FAILURE(_ret) \
63 fprintf(stderr, "\tTest step failure: %d at %s:%d\n", \
64 _ret, __func__, __LINE__); \
69 asm volatile(" rd %%tick, %0\n" : "=r" (_x))
71 static int random_version(void)
77 return tick
% (ADI_MAX_VERSION
+ 1);
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
];
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};
104 static void update_stats(struct stats
* const ustats
,
105 unsigned long measurement
, unsigned long bytes
)
107 ustats
->total
+= measurement
;
108 ustats
->bytes
+= bytes
;
112 static void print_ustats(const struct stats
* const ustats
)
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
);
120 static void print_stats(void)
122 DEBUG_PRINT_L1("\nSyscall\tCall\tAvgTime\tAvgSize\n"
123 "\tCount\t(ticks)\t(bytes)\n"
124 "-------------------------------\n");
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
);
133 static int build_memory_map(void)
141 fp
= fopen("/proc/iomem", "r");
143 fprintf(stderr
, "/proc/iomem: error %d: %s\n",
144 errno
, strerror(errno
));
148 while (fgets(line
, sizeof(line
), fp
) != 0) {
149 if (strstr(line
, system_ram_str
)) {
150 char *dash
, *end_ptr
;
152 /* Given a line like this:
153 * d0400000-10ffaffff : System RAM
154 * replace the "-" with a space
156 dash
= strstr(line
, "-");
159 start_addr
[range_count
] = strtoull(line
, &end_ptr
, 16);
160 end_addr
[range_count
] = strtoull(end_ptr
, NULL
, 16);
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
]);
172 if (range_count
== 0) {
173 fprintf(stderr
, "No valid address ranges found. Error.\n");
180 static int read_adi(int fd
, unsigned char *buf
, int buf_sz
)
182 int ret
, bytes_read
= 0;
183 long start
, end
, elapsed_time
= 0;
187 ret
= read(fd
, buf
+ bytes_read
, buf_sz
- bytes_read
);
192 elapsed_time
+= end
- start
;
193 update_stats(&read_stats
, elapsed_time
, buf_sz
);
196 } while (bytes_read
< buf_sz
);
198 DEBUG_PRINT_T("\tread elapsed timed = %ld\n", elapsed_time
);
199 DEBUG_PRINT_L3("\tRead %d bytes\n", bytes_read
);
204 static int pread_adi(int fd
, unsigned char *buf
,
205 int buf_sz
, unsigned long offset
)
207 int ret
, i
, bytes_read
= 0;
208 unsigned long cur_offset
;
209 long start
, end
, elapsed_time
= 0;
214 ret
= pread(fd
, buf
+ bytes_read
, buf_sz
- bytes_read
,
220 elapsed_time
+= end
- start
;
221 update_stats(&pread_stats
, elapsed_time
, buf_sz
);
225 } while (bytes_read
< buf_sz
);
227 DEBUG_PRINT_T("\tpread elapsed timed = %ld\n", elapsed_time
);
228 DEBUG_PRINT_L3("\tRead %d bytes starting at offset 0x%lx\n",
230 for (i
= 0; i
< bytes_read
; i
++)
231 DEBUG_PRINT_L4("\t\t0x%lx\t%d\n", offset
+ i
, buf
[i
]);
236 static int write_adi(int fd
, const unsigned char * const buf
, int buf_sz
)
238 int ret
, bytes_written
= 0;
239 long start
, end
, elapsed_time
= 0;
243 ret
= write(fd
, buf
+ bytes_written
, buf_sz
- bytes_written
);
248 elapsed_time
+= (end
- start
);
249 update_stats(&write_stats
, elapsed_time
, buf_sz
);
250 bytes_written
+= ret
;
251 } while (bytes_written
< buf_sz
);
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
);
256 return bytes_written
;
259 static int pwrite_adi(int fd
, const unsigned char * const buf
,
260 int buf_sz
, unsigned long offset
)
262 int ret
, bytes_written
= 0;
263 unsigned long cur_offset
;
264 long start
, end
, elapsed_time
= 0;
270 ret
= pwrite(fd
, buf
+ bytes_written
,
271 buf_sz
- bytes_written
, cur_offset
);
274 fprintf(stderr
, "pwrite(): error %d: %s\n",
275 errno
, strerror(errno
));
279 elapsed_time
+= (end
- start
);
280 update_stats(&pwrite_stats
, elapsed_time
, buf_sz
);
281 bytes_written
+= ret
;
284 } while (bytes_written
< buf_sz
);
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
);
290 return bytes_written
;
293 static off_t
seek_adi(int fd
, off_t offset
, int whence
)
299 ret
= lseek(fd
, offset
, whence
);
301 DEBUG_PRINT_L2("\tlseek ret = 0x%llx\n", ret
);
305 DEBUG_PRINT_T("\tlseek elapsed timed = %ld\n", end
- start
);
306 update_stats(&seek_stats
, end
- start
, 0);
309 (void)lseek(fd
, 0, SEEK_END
);
313 static int test0_prpw_aligned_1byte(int fd
)
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
;
322 version
[0] = random_version();
323 expected_version
= version
[0];
325 offset
= paddr
/ ADI_BLKSZ
;
327 ret
= pwrite_adi(fd
, version
, sizeof(version
), offset
);
328 if (ret
!= sizeof(version
))
329 TEST_STEP_FAILURE(ret
);
331 ret
= pread_adi(fd
, version
, sizeof(version
), offset
);
332 if (ret
!= sizeof(version
))
333 TEST_STEP_FAILURE(ret
);
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
);
343 RETURN_FROM_TEST(ret
);
346 #define TEST1_VERSION_SZ 4096
347 static int test1_prpw_aligned_4096bytes(int fd
)
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
];
357 for (i
= 0; i
< TEST1_VERSION_SZ
; i
++) {
358 version
[i
] = random_version();
359 expected_version
[i
] = version
[i
];
362 offset
= paddr
/ ADI_BLKSZ
;
364 ret
= pwrite_adi(fd
, version
, sizeof(version
), offset
);
365 if (ret
!= sizeof(version
))
366 TEST_STEP_FAILURE(ret
);
368 ret
= pread_adi(fd
, version
, sizeof(version
), offset
);
369 if (ret
!= sizeof(version
))
370 TEST_STEP_FAILURE(ret
);
372 for (i
= 0; i
< TEST1_VERSION_SZ
; i
++) {
373 if (expected_version
[i
] != version
[i
]) {
375 "\tExpected version %d but read version %d\n",
376 expected_version
, version
[0]);
377 TEST_STEP_FAILURE(-expected_version
[i
]);
383 RETURN_FROM_TEST(ret
);
386 #define TEST2_VERSION_SZ 10327
387 static int test2_prpw_aligned_10327bytes(int fd
)
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
];
397 for (i
= 0; i
< TEST2_VERSION_SZ
; i
++) {
398 version
[i
] = random_version();
399 expected_version
[i
] = version
[i
];
402 offset
= paddr
/ ADI_BLKSZ
;
404 ret
= pwrite_adi(fd
, version
, sizeof(version
), offset
);
405 if (ret
!= sizeof(version
))
406 TEST_STEP_FAILURE(ret
);
408 ret
= pread_adi(fd
, version
, sizeof(version
), offset
);
409 if (ret
!= sizeof(version
))
410 TEST_STEP_FAILURE(ret
);
412 for (i
= 0; i
< TEST2_VERSION_SZ
; i
++) {
413 if (expected_version
[i
] != version
[i
]) {
415 "\tExpected version %d but read version %d\n",
416 expected_version
, version
[0]);
417 TEST_STEP_FAILURE(-expected_version
[i
]);
423 RETURN_FROM_TEST(ret
);
426 #define TEST3_VERSION_SZ 12541
427 static int test3_prpw_unaligned_12541bytes(int fd
)
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
];
437 for (i
= 0; i
< TEST3_VERSION_SZ
; i
++) {
438 version
[i
] = random_version();
439 expected_version
[i
] = version
[i
];
442 offset
= paddr
/ ADI_BLKSZ
;
444 ret
= pwrite_adi(fd
, version
, sizeof(version
), offset
);
445 if (ret
!= sizeof(version
))
446 TEST_STEP_FAILURE(ret
);
448 ret
= pread_adi(fd
, version
, sizeof(version
), offset
);
449 if (ret
!= sizeof(version
))
450 TEST_STEP_FAILURE(ret
);
452 for (i
= 0; i
< TEST3_VERSION_SZ
; i
++) {
453 if (expected_version
[i
] != version
[i
]) {
455 "\tExpected version %d but read version %d\n",
456 expected_version
, version
[0]);
457 TEST_STEP_FAILURE(-expected_version
[i
]);
463 RETURN_FROM_TEST(ret
);
466 static int test4_lseek(int fd
)
468 #define OFFSET_ADD (0x100)
469 #define OFFSET_SUBTRACT (0xFFFFFFF000000000)
471 off_t offset_out
, offset_in
;
475 offset_in
= 0x123456789abcdef0;
476 offset_out
= seek_adi(fd
, offset_in
, SEEK_SET
);
477 if (offset_out
!= offset_in
) {
479 TEST_STEP_FAILURE(ret
);
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
)
486 "\tSEEK_SET failed as designed. Not an error\n");
489 TEST_STEP_FAILURE(ret
);
492 offset_out
= seek_adi(fd
, 0, SEEK_CUR
);
493 if (offset_out
!= offset_in
) {
495 TEST_STEP_FAILURE(ret
);
498 offset_out
= seek_adi(fd
, OFFSET_ADD
, SEEK_CUR
);
499 if (offset_out
!= (offset_in
+ OFFSET_ADD
)) {
501 TEST_STEP_FAILURE(ret
);
504 offset_out
= seek_adi(fd
, OFFSET_SUBTRACT
, SEEK_CUR
);
505 if (offset_out
!= (offset_in
+ OFFSET_ADD
+ OFFSET_SUBTRACT
)) {
507 TEST_STEP_FAILURE(ret
);
512 RETURN_FROM_TEST(ret
);
515 static int test5_rw_aligned_1byte(int fd
)
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
;
525 offset
= paddr
/ ADI_BLKSZ
;
526 version
= expected_version
= random_version();
528 oret
= seek_adi(fd
, offset
, SEEK_SET
);
529 if (oret
!= offset
) {
531 TEST_STEP_FAILURE(ret
);
534 ret
= write_adi(fd
, &version
, sizeof(version
));
535 if (ret
!= sizeof(version
))
536 TEST_STEP_FAILURE(ret
);
538 oret
= seek_adi(fd
, offset
, SEEK_SET
);
539 if (oret
!= offset
) {
541 TEST_STEP_FAILURE(ret
);
544 ret
= read_adi(fd
, &version
, sizeof(version
));
545 if (ret
!= sizeof(version
))
546 TEST_STEP_FAILURE(ret
);
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
);
556 RETURN_FROM_TEST(ret
);
559 #define TEST6_VERSION_SZ 9434
560 static int test6_rw_aligned_9434bytes(int fd
)
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
];
571 offset
= paddr
/ ADI_BLKSZ
;
572 for (i
= 0; i
< TEST6_VERSION_SZ
; i
++)
573 version
[i
] = expected_version
[i
] = random_version();
575 oret
= seek_adi(fd
, offset
, SEEK_SET
);
576 if (oret
!= offset
) {
578 TEST_STEP_FAILURE(ret
);
581 ret
= write_adi(fd
, version
, sizeof(version
));
582 if (ret
!= sizeof(version
))
583 TEST_STEP_FAILURE(ret
);
585 memset(version
, 0, TEST6_VERSION_SZ
);
587 oret
= seek_adi(fd
, offset
, SEEK_SET
);
588 if (oret
!= offset
) {
590 TEST_STEP_FAILURE(ret
);
593 ret
= read_adi(fd
, version
, sizeof(version
));
594 if (ret
!= sizeof(version
))
595 TEST_STEP_FAILURE(ret
);
597 for (i
= 0; i
< TEST6_VERSION_SZ
; i
++) {
598 if (expected_version
[i
] != version
[i
]) {
600 "\tExpected version %d but read version %d\n",
601 expected_version
[i
], version
[i
]);
602 TEST_STEP_FAILURE(-expected_version
[i
]);
608 RETURN_FROM_TEST(ret
);
611 #define TEST7_VERSION_SZ 14963
612 static int test7_rw_aligned_14963bytes(int fd
)
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
];
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
];
629 oret
= seek_adi(fd
, offset
, SEEK_SET
);
630 if (oret
!= offset
) {
632 TEST_STEP_FAILURE(ret
);
635 ret
= write_adi(fd
, version
, sizeof(version
));
636 if (ret
!= sizeof(version
))
637 TEST_STEP_FAILURE(ret
);
639 memset(version
, 0, TEST7_VERSION_SZ
);
641 oret
= seek_adi(fd
, offset
, SEEK_SET
);
642 if (oret
!= offset
) {
644 TEST_STEP_FAILURE(ret
);
647 ret
= read_adi(fd
, version
, sizeof(version
));
648 if (ret
!= sizeof(version
))
649 TEST_STEP_FAILURE(ret
);
651 for (i
= 0; i
< TEST7_VERSION_SZ
; i
++) {
652 if (expected_version
[i
] != version
[i
]) {
654 "\tExpected version %d but read version %d\n",
655 expected_version
[i
], version
[i
]);
656 TEST_STEP_FAILURE(-expected_version
[i
]);
664 RETURN_FROM_TEST(ret
);
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
,
673 test5_rw_aligned_1byte
,
674 test6_rw_aligned_9434bytes
,
675 test7_rw_aligned_14963bytes
,
677 #define TEST_COUNT ARRAY_SIZE(tests)
679 int main(int argc
, char *argv
[])
683 ret
= build_memory_map();
687 fd
= open("/dev/adi", O_RDWR
);
689 fprintf(stderr
, "open: error %d: %s\n",
690 errno
, strerror(errno
));
694 for (test
= 0; test
< TEST_COUNT
; test
++) {
695 DEBUG_PRINT_L1("Running test #%d\n", test
);
697 ret
= (*tests
[test
])(fd
);
699 ksft_test_result_fail("Test #%d failed: error %d\n",
702 ksft_test_result_pass("Test #%d passed\n", test
);
708 if (ksft_get_fail_cnt() > 0)
713 /* it's impossible to get here, but the compiler throws a warning
714 * about control reaching the end of non-void function. bah.