162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * selftest for sparc64's privileged ADI driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Tom Hromatka <tom.hromatka@oracle.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <errno.h> 962306a36Sopenharmony_ci#include <fcntl.h> 1062306a36Sopenharmony_ci#include <stdarg.h> 1162306a36Sopenharmony_ci#include <stdio.h> 1262306a36Sopenharmony_ci#include <stdlib.h> 1362306a36Sopenharmony_ci#include <string.h> 1462306a36Sopenharmony_ci#include <sys/syscall.h> 1562306a36Sopenharmony_ci#include <sys/types.h> 1662306a36Sopenharmony_ci#include <sys/stat.h> 1762306a36Sopenharmony_ci#include <unistd.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "../../kselftest.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define DEBUG_LEVEL_1_BIT (0x0001) 2262306a36Sopenharmony_ci#define DEBUG_LEVEL_2_BIT (0x0002) 2362306a36Sopenharmony_ci#define DEBUG_LEVEL_3_BIT (0x0004) 2462306a36Sopenharmony_ci#define DEBUG_LEVEL_4_BIT (0x0008) 2562306a36Sopenharmony_ci#define DEBUG_TIMING_BIT (0x1000) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* bit mask of enabled bits to print */ 2862306a36Sopenharmony_ci#define DEBUG 0x0001 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define DEBUG_PRINT_L1(...) debug_print(DEBUG_LEVEL_1_BIT, __VA_ARGS__) 3162306a36Sopenharmony_ci#define DEBUG_PRINT_L2(...) debug_print(DEBUG_LEVEL_2_BIT, __VA_ARGS__) 3262306a36Sopenharmony_ci#define DEBUG_PRINT_L3(...) debug_print(DEBUG_LEVEL_3_BIT, __VA_ARGS__) 3362306a36Sopenharmony_ci#define DEBUG_PRINT_L4(...) debug_print(DEBUG_LEVEL_4_BIT, __VA_ARGS__) 3462306a36Sopenharmony_ci#define DEBUG_PRINT_T(...) debug_print(DEBUG_TIMING_BIT, __VA_ARGS__) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic void debug_print(int level, const char *s, ...) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci va_list args; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci va_start(args, s); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (DEBUG & level) 4362306a36Sopenharmony_ci vfprintf(stdout, s, args); 4462306a36Sopenharmony_ci va_end(args); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#ifndef min 4862306a36Sopenharmony_ci#define min(x, y) ((x) < (y) ? x : y) 4962306a36Sopenharmony_ci#endif 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define RETURN_FROM_TEST(_ret) \ 5262306a36Sopenharmony_ci do { \ 5362306a36Sopenharmony_ci DEBUG_PRINT_L1( \ 5462306a36Sopenharmony_ci "\tTest %s returned %d\n", __func__, _ret); \ 5562306a36Sopenharmony_ci return _ret; \ 5662306a36Sopenharmony_ci } while (0) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define ADI_BLKSZ 64 5962306a36Sopenharmony_ci#define ADI_MAX_VERSION 15 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define TEST_STEP_FAILURE(_ret) \ 6262306a36Sopenharmony_ci do { \ 6362306a36Sopenharmony_ci fprintf(stderr, "\tTest step failure: %d at %s:%d\n", \ 6462306a36Sopenharmony_ci _ret, __func__, __LINE__); \ 6562306a36Sopenharmony_ci goto out; \ 6662306a36Sopenharmony_ci } while (0) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define RDTICK(_x) \ 6962306a36Sopenharmony_ci asm volatile(" rd %%tick, %0\n" : "=r" (_x)) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int random_version(void) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci long tick; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci RDTICK(tick); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return tick % (ADI_MAX_VERSION + 1); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define MAX_RANGES_SUPPORTED 5 8162306a36Sopenharmony_cistatic const char system_ram_str[] = "System RAM\n"; 8262306a36Sopenharmony_cistatic int range_count; 8362306a36Sopenharmony_cistatic unsigned long long int start_addr[MAX_RANGES_SUPPORTED]; 8462306a36Sopenharmony_cistatic unsigned long long int end_addr[MAX_RANGES_SUPPORTED]; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistruct stats { 8762306a36Sopenharmony_ci char name[16]; 8862306a36Sopenharmony_ci unsigned long total; 8962306a36Sopenharmony_ci unsigned long count; 9062306a36Sopenharmony_ci unsigned long bytes; 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic struct stats read_stats = { 9462306a36Sopenharmony_ci .name = "read", .total = 0, .count = 0, .bytes = 0}; 9562306a36Sopenharmony_cistatic struct stats pread_stats = { 9662306a36Sopenharmony_ci .name = "pread", .total = 0, .count = 0, .bytes = 0}; 9762306a36Sopenharmony_cistatic struct stats write_stats = { 9862306a36Sopenharmony_ci .name = "write", .total = 0, .count = 0, .bytes = 0}; 9962306a36Sopenharmony_cistatic struct stats pwrite_stats = { 10062306a36Sopenharmony_ci .name = "pwrite", .total = 0, .count = 0, .bytes = 0}; 10162306a36Sopenharmony_cistatic struct stats seek_stats = { 10262306a36Sopenharmony_ci .name = "seek", .total = 0, .count = 0, .bytes = 0}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic void update_stats(struct stats * const ustats, 10562306a36Sopenharmony_ci unsigned long measurement, unsigned long bytes) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci ustats->total += measurement; 10862306a36Sopenharmony_ci ustats->bytes += bytes; 10962306a36Sopenharmony_ci ustats->count++; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void print_ustats(const struct stats * const ustats) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci DEBUG_PRINT_L1("%s\t%7d\t%7.0f\t%7.0f\n", 11562306a36Sopenharmony_ci ustats->name, ustats->count, 11662306a36Sopenharmony_ci (float)ustats->total / (float)ustats->count, 11762306a36Sopenharmony_ci (float)ustats->bytes / (float)ustats->count); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic void print_stats(void) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci DEBUG_PRINT_L1("\nSyscall\tCall\tAvgTime\tAvgSize\n" 12362306a36Sopenharmony_ci "\tCount\t(ticks)\t(bytes)\n" 12462306a36Sopenharmony_ci "-------------------------------\n"); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci print_ustats(&read_stats); 12762306a36Sopenharmony_ci print_ustats(&pread_stats); 12862306a36Sopenharmony_ci print_ustats(&write_stats); 12962306a36Sopenharmony_ci print_ustats(&pwrite_stats); 13062306a36Sopenharmony_ci print_ustats(&seek_stats); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int build_memory_map(void) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci char line[256]; 13662306a36Sopenharmony_ci FILE *fp; 13762306a36Sopenharmony_ci int i; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci range_count = 0; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci fp = fopen("/proc/iomem", "r"); 14262306a36Sopenharmony_ci if (!fp) { 14362306a36Sopenharmony_ci fprintf(stderr, "/proc/iomem: error %d: %s\n", 14462306a36Sopenharmony_ci errno, strerror(errno)); 14562306a36Sopenharmony_ci return -errno; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci while (fgets(line, sizeof(line), fp) != 0) { 14962306a36Sopenharmony_ci if (strstr(line, system_ram_str)) { 15062306a36Sopenharmony_ci char *dash, *end_ptr; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Given a line like this: 15362306a36Sopenharmony_ci * d0400000-10ffaffff : System RAM 15462306a36Sopenharmony_ci * replace the "-" with a space 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci dash = strstr(line, "-"); 15762306a36Sopenharmony_ci dash[0] = 0x20; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci start_addr[range_count] = strtoull(line, &end_ptr, 16); 16062306a36Sopenharmony_ci end_addr[range_count] = strtoull(end_ptr, NULL, 16); 16162306a36Sopenharmony_ci range_count++; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci fclose(fp); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci DEBUG_PRINT_L1("RAM Ranges\n"); 16862306a36Sopenharmony_ci for (i = 0; i < range_count; i++) 16962306a36Sopenharmony_ci DEBUG_PRINT_L1("\trange %d: 0x%llx\t- 0x%llx\n", 17062306a36Sopenharmony_ci i, start_addr[i], end_addr[i]); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (range_count == 0) { 17362306a36Sopenharmony_ci fprintf(stderr, "No valid address ranges found. Error.\n"); 17462306a36Sopenharmony_ci return -1; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int read_adi(int fd, unsigned char *buf, int buf_sz) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci int ret, bytes_read = 0; 18362306a36Sopenharmony_ci long start, end, elapsed_time = 0; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci do { 18662306a36Sopenharmony_ci RDTICK(start); 18762306a36Sopenharmony_ci ret = read(fd, buf + bytes_read, buf_sz - bytes_read); 18862306a36Sopenharmony_ci RDTICK(end); 18962306a36Sopenharmony_ci if (ret < 0) 19062306a36Sopenharmony_ci return -errno; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci elapsed_time += end - start; 19362306a36Sopenharmony_ci update_stats(&read_stats, elapsed_time, buf_sz); 19462306a36Sopenharmony_ci bytes_read += ret; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci } while (bytes_read < buf_sz); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci DEBUG_PRINT_T("\tread elapsed timed = %ld\n", elapsed_time); 19962306a36Sopenharmony_ci DEBUG_PRINT_L3("\tRead %d bytes\n", bytes_read); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return bytes_read; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int pread_adi(int fd, unsigned char *buf, 20562306a36Sopenharmony_ci int buf_sz, unsigned long offset) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci int ret, i, bytes_read = 0; 20862306a36Sopenharmony_ci unsigned long cur_offset; 20962306a36Sopenharmony_ci long start, end, elapsed_time = 0; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci cur_offset = offset; 21262306a36Sopenharmony_ci do { 21362306a36Sopenharmony_ci RDTICK(start); 21462306a36Sopenharmony_ci ret = pread(fd, buf + bytes_read, buf_sz - bytes_read, 21562306a36Sopenharmony_ci cur_offset); 21662306a36Sopenharmony_ci RDTICK(end); 21762306a36Sopenharmony_ci if (ret < 0) 21862306a36Sopenharmony_ci return -errno; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci elapsed_time += end - start; 22162306a36Sopenharmony_ci update_stats(&pread_stats, elapsed_time, buf_sz); 22262306a36Sopenharmony_ci bytes_read += ret; 22362306a36Sopenharmony_ci cur_offset += ret; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci } while (bytes_read < buf_sz); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci DEBUG_PRINT_T("\tpread elapsed timed = %ld\n", elapsed_time); 22862306a36Sopenharmony_ci DEBUG_PRINT_L3("\tRead %d bytes starting at offset 0x%lx\n", 22962306a36Sopenharmony_ci bytes_read, offset); 23062306a36Sopenharmony_ci for (i = 0; i < bytes_read; i++) 23162306a36Sopenharmony_ci DEBUG_PRINT_L4("\t\t0x%lx\t%d\n", offset + i, buf[i]); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return bytes_read; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int write_adi(int fd, const unsigned char * const buf, int buf_sz) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci int ret, bytes_written = 0; 23962306a36Sopenharmony_ci long start, end, elapsed_time = 0; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci do { 24262306a36Sopenharmony_ci RDTICK(start); 24362306a36Sopenharmony_ci ret = write(fd, buf + bytes_written, buf_sz - bytes_written); 24462306a36Sopenharmony_ci RDTICK(end); 24562306a36Sopenharmony_ci if (ret < 0) 24662306a36Sopenharmony_ci return -errno; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci elapsed_time += (end - start); 24962306a36Sopenharmony_ci update_stats(&write_stats, elapsed_time, buf_sz); 25062306a36Sopenharmony_ci bytes_written += ret; 25162306a36Sopenharmony_ci } while (bytes_written < buf_sz); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci DEBUG_PRINT_T("\twrite elapsed timed = %ld\n", elapsed_time); 25462306a36Sopenharmony_ci DEBUG_PRINT_L3("\tWrote %d of %d bytes\n", bytes_written, buf_sz); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return bytes_written; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int pwrite_adi(int fd, const unsigned char * const buf, 26062306a36Sopenharmony_ci int buf_sz, unsigned long offset) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci int ret, bytes_written = 0; 26362306a36Sopenharmony_ci unsigned long cur_offset; 26462306a36Sopenharmony_ci long start, end, elapsed_time = 0; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci cur_offset = offset; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci do { 26962306a36Sopenharmony_ci RDTICK(start); 27062306a36Sopenharmony_ci ret = pwrite(fd, buf + bytes_written, 27162306a36Sopenharmony_ci buf_sz - bytes_written, cur_offset); 27262306a36Sopenharmony_ci RDTICK(end); 27362306a36Sopenharmony_ci if (ret < 0) { 27462306a36Sopenharmony_ci fprintf(stderr, "pwrite(): error %d: %s\n", 27562306a36Sopenharmony_ci errno, strerror(errno)); 27662306a36Sopenharmony_ci return -errno; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci elapsed_time += (end - start); 28062306a36Sopenharmony_ci update_stats(&pwrite_stats, elapsed_time, buf_sz); 28162306a36Sopenharmony_ci bytes_written += ret; 28262306a36Sopenharmony_ci cur_offset += ret; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci } while (bytes_written < buf_sz); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci DEBUG_PRINT_T("\tpwrite elapsed timed = %ld\n", elapsed_time); 28762306a36Sopenharmony_ci DEBUG_PRINT_L3("\tWrote %d of %d bytes starting at address 0x%lx\n", 28862306a36Sopenharmony_ci bytes_written, buf_sz, offset); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return bytes_written; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic off_t seek_adi(int fd, off_t offset, int whence) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci long start, end; 29662306a36Sopenharmony_ci off_t ret; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci RDTICK(start); 29962306a36Sopenharmony_ci ret = lseek(fd, offset, whence); 30062306a36Sopenharmony_ci RDTICK(end); 30162306a36Sopenharmony_ci DEBUG_PRINT_L2("\tlseek ret = 0x%llx\n", ret); 30262306a36Sopenharmony_ci if (ret < 0) 30362306a36Sopenharmony_ci goto out; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci DEBUG_PRINT_T("\tlseek elapsed timed = %ld\n", end - start); 30662306a36Sopenharmony_ci update_stats(&seek_stats, end - start, 0); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ciout: 30962306a36Sopenharmony_ci (void)lseek(fd, 0, SEEK_END); 31062306a36Sopenharmony_ci return ret; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int test0_prpw_aligned_1byte(int fd) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci /* somewhat arbitrarily chosen address */ 31662306a36Sopenharmony_ci unsigned long paddr = 31762306a36Sopenharmony_ci (end_addr[range_count - 1] - 0x1000) & ~(ADI_BLKSZ - 1); 31862306a36Sopenharmony_ci unsigned char version[1], expected_version; 31962306a36Sopenharmony_ci loff_t offset; 32062306a36Sopenharmony_ci int ret; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci version[0] = random_version(); 32362306a36Sopenharmony_ci expected_version = version[0]; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci offset = paddr / ADI_BLKSZ; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ret = pwrite_adi(fd, version, sizeof(version), offset); 32862306a36Sopenharmony_ci if (ret != sizeof(version)) 32962306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci ret = pread_adi(fd, version, sizeof(version), offset); 33262306a36Sopenharmony_ci if (ret != sizeof(version)) 33362306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (expected_version != version[0]) { 33662306a36Sopenharmony_ci DEBUG_PRINT_L2("\tExpected version %d but read version %d\n", 33762306a36Sopenharmony_ci expected_version, version[0]); 33862306a36Sopenharmony_ci TEST_STEP_FAILURE(-expected_version); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ret = 0; 34262306a36Sopenharmony_ciout: 34362306a36Sopenharmony_ci RETURN_FROM_TEST(ret); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci#define TEST1_VERSION_SZ 4096 34762306a36Sopenharmony_cistatic int test1_prpw_aligned_4096bytes(int fd) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci /* somewhat arbitrarily chosen address */ 35062306a36Sopenharmony_ci unsigned long paddr = 35162306a36Sopenharmony_ci (end_addr[range_count - 1] - 0x6000) & ~(ADI_BLKSZ - 1); 35262306a36Sopenharmony_ci unsigned char version[TEST1_VERSION_SZ], 35362306a36Sopenharmony_ci expected_version[TEST1_VERSION_SZ]; 35462306a36Sopenharmony_ci loff_t offset; 35562306a36Sopenharmony_ci int ret, i; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci for (i = 0; i < TEST1_VERSION_SZ; i++) { 35862306a36Sopenharmony_ci version[i] = random_version(); 35962306a36Sopenharmony_ci expected_version[i] = version[i]; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci offset = paddr / ADI_BLKSZ; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci ret = pwrite_adi(fd, version, sizeof(version), offset); 36562306a36Sopenharmony_ci if (ret != sizeof(version)) 36662306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci ret = pread_adi(fd, version, sizeof(version), offset); 36962306a36Sopenharmony_ci if (ret != sizeof(version)) 37062306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci for (i = 0; i < TEST1_VERSION_SZ; i++) { 37362306a36Sopenharmony_ci if (expected_version[i] != version[i]) { 37462306a36Sopenharmony_ci DEBUG_PRINT_L2( 37562306a36Sopenharmony_ci "\tExpected version %d but read version %d\n", 37662306a36Sopenharmony_ci expected_version, version[0]); 37762306a36Sopenharmony_ci TEST_STEP_FAILURE(-expected_version[i]); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci ret = 0; 38262306a36Sopenharmony_ciout: 38362306a36Sopenharmony_ci RETURN_FROM_TEST(ret); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci#define TEST2_VERSION_SZ 10327 38762306a36Sopenharmony_cistatic int test2_prpw_aligned_10327bytes(int fd) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci /* somewhat arbitrarily chosen address */ 39062306a36Sopenharmony_ci unsigned long paddr = 39162306a36Sopenharmony_ci (start_addr[0] + 0x6000) & ~(ADI_BLKSZ - 1); 39262306a36Sopenharmony_ci unsigned char version[TEST2_VERSION_SZ], 39362306a36Sopenharmony_ci expected_version[TEST2_VERSION_SZ]; 39462306a36Sopenharmony_ci loff_t offset; 39562306a36Sopenharmony_ci int ret, i; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci for (i = 0; i < TEST2_VERSION_SZ; i++) { 39862306a36Sopenharmony_ci version[i] = random_version(); 39962306a36Sopenharmony_ci expected_version[i] = version[i]; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci offset = paddr / ADI_BLKSZ; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci ret = pwrite_adi(fd, version, sizeof(version), offset); 40562306a36Sopenharmony_ci if (ret != sizeof(version)) 40662306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci ret = pread_adi(fd, version, sizeof(version), offset); 40962306a36Sopenharmony_ci if (ret != sizeof(version)) 41062306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci for (i = 0; i < TEST2_VERSION_SZ; i++) { 41362306a36Sopenharmony_ci if (expected_version[i] != version[i]) { 41462306a36Sopenharmony_ci DEBUG_PRINT_L2( 41562306a36Sopenharmony_ci "\tExpected version %d but read version %d\n", 41662306a36Sopenharmony_ci expected_version, version[0]); 41762306a36Sopenharmony_ci TEST_STEP_FAILURE(-expected_version[i]); 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci ret = 0; 42262306a36Sopenharmony_ciout: 42362306a36Sopenharmony_ci RETURN_FROM_TEST(ret); 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci#define TEST3_VERSION_SZ 12541 42762306a36Sopenharmony_cistatic int test3_prpw_unaligned_12541bytes(int fd) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci /* somewhat arbitrarily chosen address */ 43062306a36Sopenharmony_ci unsigned long paddr = 43162306a36Sopenharmony_ci ((start_addr[0] + 0xC000) & ~(ADI_BLKSZ - 1)) + 17; 43262306a36Sopenharmony_ci unsigned char version[TEST3_VERSION_SZ], 43362306a36Sopenharmony_ci expected_version[TEST3_VERSION_SZ]; 43462306a36Sopenharmony_ci loff_t offset; 43562306a36Sopenharmony_ci int ret, i; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci for (i = 0; i < TEST3_VERSION_SZ; i++) { 43862306a36Sopenharmony_ci version[i] = random_version(); 43962306a36Sopenharmony_ci expected_version[i] = version[i]; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci offset = paddr / ADI_BLKSZ; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci ret = pwrite_adi(fd, version, sizeof(version), offset); 44562306a36Sopenharmony_ci if (ret != sizeof(version)) 44662306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci ret = pread_adi(fd, version, sizeof(version), offset); 44962306a36Sopenharmony_ci if (ret != sizeof(version)) 45062306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci for (i = 0; i < TEST3_VERSION_SZ; i++) { 45362306a36Sopenharmony_ci if (expected_version[i] != version[i]) { 45462306a36Sopenharmony_ci DEBUG_PRINT_L2( 45562306a36Sopenharmony_ci "\tExpected version %d but read version %d\n", 45662306a36Sopenharmony_ci expected_version, version[0]); 45762306a36Sopenharmony_ci TEST_STEP_FAILURE(-expected_version[i]); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci ret = 0; 46262306a36Sopenharmony_ciout: 46362306a36Sopenharmony_ci RETURN_FROM_TEST(ret); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic int test4_lseek(int fd) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci#define OFFSET_ADD (0x100) 46962306a36Sopenharmony_ci#define OFFSET_SUBTRACT (0xFFFFFFF000000000) 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci off_t offset_out, offset_in; 47262306a36Sopenharmony_ci int ret; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci offset_in = 0x123456789abcdef0; 47662306a36Sopenharmony_ci offset_out = seek_adi(fd, offset_in, SEEK_SET); 47762306a36Sopenharmony_ci if (offset_out != offset_in) { 47862306a36Sopenharmony_ci ret = -1; 47962306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* seek to the current offset. this should return EINVAL */ 48362306a36Sopenharmony_ci offset_out = seek_adi(fd, offset_in, SEEK_SET); 48462306a36Sopenharmony_ci if (offset_out < 0 && errno == EINVAL) 48562306a36Sopenharmony_ci DEBUG_PRINT_L2( 48662306a36Sopenharmony_ci "\tSEEK_SET failed as designed. Not an error\n"); 48762306a36Sopenharmony_ci else { 48862306a36Sopenharmony_ci ret = -2; 48962306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci offset_out = seek_adi(fd, 0, SEEK_CUR); 49362306a36Sopenharmony_ci if (offset_out != offset_in) { 49462306a36Sopenharmony_ci ret = -3; 49562306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci offset_out = seek_adi(fd, OFFSET_ADD, SEEK_CUR); 49962306a36Sopenharmony_ci if (offset_out != (offset_in + OFFSET_ADD)) { 50062306a36Sopenharmony_ci ret = -4; 50162306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci offset_out = seek_adi(fd, OFFSET_SUBTRACT, SEEK_CUR); 50562306a36Sopenharmony_ci if (offset_out != (offset_in + OFFSET_ADD + OFFSET_SUBTRACT)) { 50662306a36Sopenharmony_ci ret = -5; 50762306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ret = 0; 51162306a36Sopenharmony_ciout: 51262306a36Sopenharmony_ci RETURN_FROM_TEST(ret); 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic int test5_rw_aligned_1byte(int fd) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci /* somewhat arbitrarily chosen address */ 51862306a36Sopenharmony_ci unsigned long paddr = 51962306a36Sopenharmony_ci (end_addr[range_count - 1] - 0xF000) & ~(ADI_BLKSZ - 1); 52062306a36Sopenharmony_ci unsigned char version, expected_version; 52162306a36Sopenharmony_ci loff_t offset; 52262306a36Sopenharmony_ci off_t oret; 52362306a36Sopenharmony_ci int ret; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci offset = paddr / ADI_BLKSZ; 52662306a36Sopenharmony_ci version = expected_version = random_version(); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci oret = seek_adi(fd, offset, SEEK_SET); 52962306a36Sopenharmony_ci if (oret != offset) { 53062306a36Sopenharmony_ci ret = -1; 53162306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci ret = write_adi(fd, &version, sizeof(version)); 53562306a36Sopenharmony_ci if (ret != sizeof(version)) 53662306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci oret = seek_adi(fd, offset, SEEK_SET); 53962306a36Sopenharmony_ci if (oret != offset) { 54062306a36Sopenharmony_ci ret = -1; 54162306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci ret = read_adi(fd, &version, sizeof(version)); 54562306a36Sopenharmony_ci if (ret != sizeof(version)) 54662306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (expected_version != version) { 54962306a36Sopenharmony_ci DEBUG_PRINT_L2("\tExpected version %d but read version %d\n", 55062306a36Sopenharmony_ci expected_version, version); 55162306a36Sopenharmony_ci TEST_STEP_FAILURE(-expected_version); 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci ret = 0; 55562306a36Sopenharmony_ciout: 55662306a36Sopenharmony_ci RETURN_FROM_TEST(ret); 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci#define TEST6_VERSION_SZ 9434 56062306a36Sopenharmony_cistatic int test6_rw_aligned_9434bytes(int fd) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci /* somewhat arbitrarily chosen address */ 56362306a36Sopenharmony_ci unsigned long paddr = 56462306a36Sopenharmony_ci (end_addr[range_count - 1] - 0x5F000) & ~(ADI_BLKSZ - 1); 56562306a36Sopenharmony_ci unsigned char version[TEST6_VERSION_SZ], 56662306a36Sopenharmony_ci expected_version[TEST6_VERSION_SZ]; 56762306a36Sopenharmony_ci loff_t offset; 56862306a36Sopenharmony_ci off_t oret; 56962306a36Sopenharmony_ci int ret, i; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci offset = paddr / ADI_BLKSZ; 57262306a36Sopenharmony_ci for (i = 0; i < TEST6_VERSION_SZ; i++) 57362306a36Sopenharmony_ci version[i] = expected_version[i] = random_version(); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci oret = seek_adi(fd, offset, SEEK_SET); 57662306a36Sopenharmony_ci if (oret != offset) { 57762306a36Sopenharmony_ci ret = -1; 57862306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci ret = write_adi(fd, version, sizeof(version)); 58262306a36Sopenharmony_ci if (ret != sizeof(version)) 58362306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci memset(version, 0, TEST6_VERSION_SZ); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci oret = seek_adi(fd, offset, SEEK_SET); 58862306a36Sopenharmony_ci if (oret != offset) { 58962306a36Sopenharmony_ci ret = -1; 59062306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci ret = read_adi(fd, version, sizeof(version)); 59462306a36Sopenharmony_ci if (ret != sizeof(version)) 59562306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci for (i = 0; i < TEST6_VERSION_SZ; i++) { 59862306a36Sopenharmony_ci if (expected_version[i] != version[i]) { 59962306a36Sopenharmony_ci DEBUG_PRINT_L2( 60062306a36Sopenharmony_ci "\tExpected version %d but read version %d\n", 60162306a36Sopenharmony_ci expected_version[i], version[i]); 60262306a36Sopenharmony_ci TEST_STEP_FAILURE(-expected_version[i]); 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci ret = 0; 60762306a36Sopenharmony_ciout: 60862306a36Sopenharmony_ci RETURN_FROM_TEST(ret); 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci#define TEST7_VERSION_SZ 14963 61262306a36Sopenharmony_cistatic int test7_rw_aligned_14963bytes(int fd) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci /* somewhat arbitrarily chosen address */ 61562306a36Sopenharmony_ci unsigned long paddr = 61662306a36Sopenharmony_ci ((start_addr[range_count - 1] + 0xF000) & ~(ADI_BLKSZ - 1)) + 39; 61762306a36Sopenharmony_ci unsigned char version[TEST7_VERSION_SZ], 61862306a36Sopenharmony_ci expected_version[TEST7_VERSION_SZ]; 61962306a36Sopenharmony_ci loff_t offset; 62062306a36Sopenharmony_ci off_t oret; 62162306a36Sopenharmony_ci int ret, i; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci offset = paddr / ADI_BLKSZ; 62462306a36Sopenharmony_ci for (i = 0; i < TEST7_VERSION_SZ; i++) { 62562306a36Sopenharmony_ci version[i] = random_version(); 62662306a36Sopenharmony_ci expected_version[i] = version[i]; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci oret = seek_adi(fd, offset, SEEK_SET); 63062306a36Sopenharmony_ci if (oret != offset) { 63162306a36Sopenharmony_ci ret = -1; 63262306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci ret = write_adi(fd, version, sizeof(version)); 63662306a36Sopenharmony_ci if (ret != sizeof(version)) 63762306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci memset(version, 0, TEST7_VERSION_SZ); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci oret = seek_adi(fd, offset, SEEK_SET); 64262306a36Sopenharmony_ci if (oret != offset) { 64362306a36Sopenharmony_ci ret = -1; 64462306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci ret = read_adi(fd, version, sizeof(version)); 64862306a36Sopenharmony_ci if (ret != sizeof(version)) 64962306a36Sopenharmony_ci TEST_STEP_FAILURE(ret); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci for (i = 0; i < TEST7_VERSION_SZ; i++) { 65262306a36Sopenharmony_ci if (expected_version[i] != version[i]) { 65362306a36Sopenharmony_ci DEBUG_PRINT_L2( 65462306a36Sopenharmony_ci "\tExpected version %d but read version %d\n", 65562306a36Sopenharmony_ci expected_version[i], version[i]); 65662306a36Sopenharmony_ci TEST_STEP_FAILURE(-expected_version[i]); 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci paddr += ADI_BLKSZ; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci ret = 0; 66362306a36Sopenharmony_ciout: 66462306a36Sopenharmony_ci RETURN_FROM_TEST(ret); 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic int (*tests[])(int fd) = { 66862306a36Sopenharmony_ci test0_prpw_aligned_1byte, 66962306a36Sopenharmony_ci test1_prpw_aligned_4096bytes, 67062306a36Sopenharmony_ci test2_prpw_aligned_10327bytes, 67162306a36Sopenharmony_ci test3_prpw_unaligned_12541bytes, 67262306a36Sopenharmony_ci test4_lseek, 67362306a36Sopenharmony_ci test5_rw_aligned_1byte, 67462306a36Sopenharmony_ci test6_rw_aligned_9434bytes, 67562306a36Sopenharmony_ci test7_rw_aligned_14963bytes, 67662306a36Sopenharmony_ci}; 67762306a36Sopenharmony_ci#define TEST_COUNT ARRAY_SIZE(tests) 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ciint main(int argc, char *argv[]) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci int fd, ret, test; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci ret = build_memory_map(); 68462306a36Sopenharmony_ci if (ret < 0) 68562306a36Sopenharmony_ci return ret; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci fd = open("/dev/adi", O_RDWR); 68862306a36Sopenharmony_ci if (fd < 0) { 68962306a36Sopenharmony_ci fprintf(stderr, "open: error %d: %s\n", 69062306a36Sopenharmony_ci errno, strerror(errno)); 69162306a36Sopenharmony_ci return -errno; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci for (test = 0; test < TEST_COUNT; test++) { 69562306a36Sopenharmony_ci DEBUG_PRINT_L1("Running test #%d\n", test); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci ret = (*tests[test])(fd); 69862306a36Sopenharmony_ci if (ret != 0) 69962306a36Sopenharmony_ci ksft_test_result_fail("Test #%d failed: error %d\n", 70062306a36Sopenharmony_ci test, ret); 70162306a36Sopenharmony_ci else 70262306a36Sopenharmony_ci ksft_test_result_pass("Test #%d passed\n", test); 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci print_stats(); 70662306a36Sopenharmony_ci close(fd); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci if (ksft_get_fail_cnt() > 0) 70962306a36Sopenharmony_ci ksft_exit_fail(); 71062306a36Sopenharmony_ci else 71162306a36Sopenharmony_ci ksft_exit_pass(); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* it's impossible to get here, but the compiler throws a warning 71462306a36Sopenharmony_ci * about control reaching the end of non-void function. bah. 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_ci return 0; 71762306a36Sopenharmony_ci} 718