1 // SPDX-License-Identifier: GPL-2.0+
4 * Copyright 2018 IBM Corporation.
5 * Copyright 2020 Canonical Ltd.
8 #define __SANE_USERSPACE_TYPES__
10 #include <sys/types.h>
19 #include "flush_utils.h"
21 int uaccess_flush_test(void)
25 int fd
, passes
= 0, iter
, rc
= 0;
26 struct perf_event_read v
;
27 __u64 l1d_misses_total
= 0;
28 unsigned long iterations
= 100000, zero_size
= 24 * 1024;
29 unsigned long l1d_misses_expected
;
32 int uaccess_flush
, uaccess_flush_orig
;
34 SKIP_IF(geteuid() != 0);
36 // The PMU event we use only works on Power7 or later
37 SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06
));
39 if (read_debugfs_int("powerpc/rfi_flush", &rfi_flush_orig
) < 0) {
40 perror("Unable to read powerpc/rfi_flush debugfs file");
44 if (read_debugfs_int("powerpc/entry_flush", &entry_flush_orig
) < 0) {
45 perror("Unable to read powerpc/entry_flush debugfs file");
49 if (read_debugfs_int("powerpc/uaccess_flush", &uaccess_flush_orig
) < 0) {
50 perror("Unable to read powerpc/entry_flush debugfs file");
54 if (rfi_flush_orig
!= 0) {
55 if (write_debugfs_int("powerpc/rfi_flush", 0) < 0) {
56 perror("error writing to powerpc/rfi_flush debugfs file");
61 if (entry_flush_orig
!= 0) {
62 if (write_debugfs_int("powerpc/entry_flush", 0) < 0) {
63 perror("error writing to powerpc/entry_flush debugfs file");
68 uaccess_flush
= uaccess_flush_orig
;
70 fd
= perf_event_open_counter(PERF_TYPE_HW_CACHE
, PERF_L1D_READ_MISS_CONFIG
, -1);
73 p
= (char *)memalign(zero_size
, CACHELINE_SIZE
);
75 FAIL_IF(perf_event_enable(fd
));
77 // disable L1 prefetching
83 * We expect to see l1d miss for each cacheline access when entry_flush
84 * is set. Allow a small variation on this.
86 l1d_misses_expected
= iterations
* (zero_size
/ CACHELINE_SIZE
- 2);
89 FAIL_IF(perf_event_reset(fd
));
91 syscall_loop_uaccess(p
, iterations
, zero_size
);
93 FAIL_IF(read(fd
, &v
, sizeof(v
)) != sizeof(v
));
95 if (uaccess_flush
&& v
.l1d_misses
>= l1d_misses_expected
)
97 else if (!uaccess_flush
&& v
.l1d_misses
< (l1d_misses_expected
/ 2))
100 l1d_misses_total
+= v
.l1d_misses
;
105 if (passes
< repetitions
) {
106 printf("FAIL (L1D misses with uaccess_flush=%d: %llu %c %lu) [%d/%d failures]\n",
107 uaccess_flush
, l1d_misses_total
, uaccess_flush
? '<' : '>',
108 uaccess_flush
? repetitions
* l1d_misses_expected
:
109 repetitions
* l1d_misses_expected
/ 2,
110 repetitions
- passes
, repetitions
);
113 printf("PASS (L1D misses with uaccess_flush=%d: %llu %c %lu) [%d/%d pass]\n",
114 uaccess_flush
, l1d_misses_total
, uaccess_flush
? '>' : '<',
115 uaccess_flush
? repetitions
* l1d_misses_expected
:
116 repetitions
* l1d_misses_expected
/ 2,
117 passes
, repetitions
);
120 if (uaccess_flush
== uaccess_flush_orig
) {
121 uaccess_flush
= !uaccess_flush_orig
;
122 if (write_debugfs_int("powerpc/uaccess_flush", uaccess_flush
) < 0) {
123 perror("error writing to powerpc/uaccess_flush debugfs file");
127 l1d_misses_total
= 0;
132 perf_event_disable(fd
);
137 if (write_debugfs_int("powerpc/rfi_flush", rfi_flush_orig
) < 0) {
138 perror("unable to restore original value of powerpc/rfi_flush debugfs file");
142 if (write_debugfs_int("powerpc/entry_flush", entry_flush_orig
) < 0) {
143 perror("unable to restore original value of powerpc/entry_flush debugfs file");
147 if (write_debugfs_int("powerpc/uaccess_flush", uaccess_flush_orig
) < 0) {
148 perror("unable to restore original value of powerpc/uaccess_flush debugfs file");
155 int main(int argc
, char *argv
[])
157 return test_harness(uaccess_flush_test
, "uaccess_flush_test");