18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * Copyright 2018 IBM Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#define __SANE_USERSPACE_TYPES__ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <sys/types.h> 108c2ecf20Sopenharmony_ci#include <stdint.h> 118c2ecf20Sopenharmony_ci#include <malloc.h> 128c2ecf20Sopenharmony_ci#include <unistd.h> 138c2ecf20Sopenharmony_ci#include <stdlib.h> 148c2ecf20Sopenharmony_ci#include <string.h> 158c2ecf20Sopenharmony_ci#include <stdio.h> 168c2ecf20Sopenharmony_ci#include "utils.h" 178c2ecf20Sopenharmony_ci#include "flush_utils.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciint rfi_flush_test(void) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci char *p; 238c2ecf20Sopenharmony_ci int repetitions = 10; 248c2ecf20Sopenharmony_ci int fd, passes = 0, iter, rc = 0; 258c2ecf20Sopenharmony_ci struct perf_event_read v; 268c2ecf20Sopenharmony_ci __u64 l1d_misses_total = 0; 278c2ecf20Sopenharmony_ci unsigned long iterations = 100000, zero_size = 24 * 1024; 288c2ecf20Sopenharmony_ci unsigned long l1d_misses_expected; 298c2ecf20Sopenharmony_ci int rfi_flush_orig, rfi_flush; 308c2ecf20Sopenharmony_ci int have_entry_flush, entry_flush_orig; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci SKIP_IF(geteuid() != 0); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci // The PMU event we use only works on Power7 or later 358c2ecf20Sopenharmony_ci SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06)); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci if (read_debugfs_file("powerpc/rfi_flush", &rfi_flush_orig) < 0) { 388c2ecf20Sopenharmony_ci perror("Unable to read powerpc/rfi_flush debugfs file"); 398c2ecf20Sopenharmony_ci SKIP_IF(1); 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (read_debugfs_file("powerpc/entry_flush", &entry_flush_orig) < 0) { 438c2ecf20Sopenharmony_ci have_entry_flush = 0; 448c2ecf20Sopenharmony_ci } else { 458c2ecf20Sopenharmony_ci have_entry_flush = 1; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (entry_flush_orig != 0) { 488c2ecf20Sopenharmony_ci if (write_debugfs_file("powerpc/entry_flush", 0) < 0) { 498c2ecf20Sopenharmony_ci perror("error writing to powerpc/entry_flush debugfs file"); 508c2ecf20Sopenharmony_ci return 1; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci rfi_flush = rfi_flush_orig; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci fd = perf_event_open_counter(PERF_TYPE_HW_CACHE, PERF_L1D_READ_MISS_CONFIG, -1); 588c2ecf20Sopenharmony_ci FAIL_IF(fd < 0); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci p = (char *)memalign(zero_size, CACHELINE_SIZE); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci FAIL_IF(perf_event_enable(fd)); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci // disable L1 prefetching 658c2ecf20Sopenharmony_ci set_dscr(1); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci iter = repetitions; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* 708c2ecf20Sopenharmony_ci * We expect to see l1d miss for each cacheline access when rfi_flush 718c2ecf20Sopenharmony_ci * is set. Allow a small variation on this. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci l1d_misses_expected = iterations * (zero_size / CACHELINE_SIZE - 2); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ciagain: 768c2ecf20Sopenharmony_ci FAIL_IF(perf_event_reset(fd)); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci syscall_loop(p, iterations, zero_size); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci FAIL_IF(read(fd, &v, sizeof(v)) != sizeof(v)); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (rfi_flush && v.l1d_misses >= l1d_misses_expected) 838c2ecf20Sopenharmony_ci passes++; 848c2ecf20Sopenharmony_ci else if (!rfi_flush && v.l1d_misses < (l1d_misses_expected / 2)) 858c2ecf20Sopenharmony_ci passes++; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci l1d_misses_total += v.l1d_misses; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci while (--iter) 908c2ecf20Sopenharmony_ci goto again; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (passes < repetitions) { 938c2ecf20Sopenharmony_ci printf("FAIL (L1D misses with rfi_flush=%d: %llu %c %lu) [%d/%d failures]\n", 948c2ecf20Sopenharmony_ci rfi_flush, l1d_misses_total, rfi_flush ? '<' : '>', 958c2ecf20Sopenharmony_ci rfi_flush ? repetitions * l1d_misses_expected : 968c2ecf20Sopenharmony_ci repetitions * l1d_misses_expected / 2, 978c2ecf20Sopenharmony_ci repetitions - passes, repetitions); 988c2ecf20Sopenharmony_ci rc = 1; 998c2ecf20Sopenharmony_ci } else 1008c2ecf20Sopenharmony_ci printf("PASS (L1D misses with rfi_flush=%d: %llu %c %lu) [%d/%d pass]\n", 1018c2ecf20Sopenharmony_ci rfi_flush, l1d_misses_total, rfi_flush ? '>' : '<', 1028c2ecf20Sopenharmony_ci rfi_flush ? repetitions * l1d_misses_expected : 1038c2ecf20Sopenharmony_ci repetitions * l1d_misses_expected / 2, 1048c2ecf20Sopenharmony_ci passes, repetitions); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (rfi_flush == rfi_flush_orig) { 1078c2ecf20Sopenharmony_ci rfi_flush = !rfi_flush_orig; 1088c2ecf20Sopenharmony_ci if (write_debugfs_file("powerpc/rfi_flush", rfi_flush) < 0) { 1098c2ecf20Sopenharmony_ci perror("error writing to powerpc/rfi_flush debugfs file"); 1108c2ecf20Sopenharmony_ci return 1; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci iter = repetitions; 1138c2ecf20Sopenharmony_ci l1d_misses_total = 0; 1148c2ecf20Sopenharmony_ci passes = 0; 1158c2ecf20Sopenharmony_ci goto again; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci perf_event_disable(fd); 1198c2ecf20Sopenharmony_ci close(fd); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci set_dscr(0); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (write_debugfs_file("powerpc/rfi_flush", rfi_flush_orig) < 0) { 1248c2ecf20Sopenharmony_ci perror("unable to restore original value of powerpc/rfi_flush debugfs file"); 1258c2ecf20Sopenharmony_ci return 1; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (have_entry_flush) { 1298c2ecf20Sopenharmony_ci if (write_debugfs_file("powerpc/entry_flush", entry_flush_orig) < 0) { 1308c2ecf20Sopenharmony_ci perror("unable to restore original value of powerpc/entry_flush " 1318c2ecf20Sopenharmony_ci "debugfs file"); 1328c2ecf20Sopenharmony_ci return 1; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return rc; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci return test_harness(rfi_flush_test, "rfi_flush_test"); 1428c2ecf20Sopenharmony_ci} 143