189a83a0cSDaniel Axtens // SPDX-License-Identifier: GPL-2.0+
289a83a0cSDaniel Axtens 
389a83a0cSDaniel Axtens /*
489a83a0cSDaniel Axtens  * Copyright 2018 IBM Corporation.
589a83a0cSDaniel Axtens  */
689a83a0cSDaniel Axtens 
789a83a0cSDaniel Axtens #define __SANE_USERSPACE_TYPES__
889a83a0cSDaniel Axtens 
989a83a0cSDaniel Axtens #include <sys/types.h>
1089a83a0cSDaniel Axtens #include <stdint.h>
1189a83a0cSDaniel Axtens #include <malloc.h>
1289a83a0cSDaniel Axtens #include <unistd.h>
1389a83a0cSDaniel Axtens #include <signal.h>
1489a83a0cSDaniel Axtens #include <stdlib.h>
1589a83a0cSDaniel Axtens #include <string.h>
1689a83a0cSDaniel Axtens #include <stdio.h>
1789a83a0cSDaniel Axtens #include "utils.h"
180d239f3bSDaniel Axtens #include "flush_utils.h"
1989a83a0cSDaniel Axtens 
entry_flush_test(void)2089a83a0cSDaniel Axtens int entry_flush_test(void)
2189a83a0cSDaniel Axtens {
2289a83a0cSDaniel Axtens 	char *p;
2389a83a0cSDaniel Axtens 	int repetitions = 10;
2489a83a0cSDaniel Axtens 	int fd, passes = 0, iter, rc = 0;
2589a83a0cSDaniel Axtens 	struct perf_event_read v;
2689a83a0cSDaniel Axtens 	__u64 l1d_misses_total = 0;
2789a83a0cSDaniel Axtens 	unsigned long iterations = 100000, zero_size = 24 * 1024;
2889a83a0cSDaniel Axtens 	unsigned long l1d_misses_expected;
2989a83a0cSDaniel Axtens 	int rfi_flush_orig;
3089a83a0cSDaniel Axtens 	int entry_flush, entry_flush_orig;
3189a83a0cSDaniel Axtens 
3289a83a0cSDaniel Axtens 	SKIP_IF(geteuid() != 0);
3389a83a0cSDaniel Axtens 
3489a83a0cSDaniel Axtens 	// The PMU event we use only works on Power7 or later
3589a83a0cSDaniel Axtens 	SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
3689a83a0cSDaniel Axtens 
37*121d340bSBenjamin Gray 	if (read_debugfs_int("powerpc/rfi_flush", &rfi_flush_orig) < 0) {
3889a83a0cSDaniel Axtens 		perror("Unable to read powerpc/rfi_flush debugfs file");
3989a83a0cSDaniel Axtens 		SKIP_IF(1);
4089a83a0cSDaniel Axtens 	}
4189a83a0cSDaniel Axtens 
42*121d340bSBenjamin Gray 	if (read_debugfs_int("powerpc/entry_flush", &entry_flush_orig) < 0) {
4389a83a0cSDaniel Axtens 		perror("Unable to read powerpc/entry_flush debugfs file");
4489a83a0cSDaniel Axtens 		SKIP_IF(1);
4589a83a0cSDaniel Axtens 	}
4689a83a0cSDaniel Axtens 
4789a83a0cSDaniel Axtens 	if (rfi_flush_orig != 0) {
48*121d340bSBenjamin Gray 		if (write_debugfs_int("powerpc/rfi_flush", 0) < 0) {
4989a83a0cSDaniel Axtens 			perror("error writing to powerpc/rfi_flush debugfs file");
5089a83a0cSDaniel Axtens 			FAIL_IF(1);
5189a83a0cSDaniel Axtens 		}
5289a83a0cSDaniel Axtens 	}
5389a83a0cSDaniel Axtens 
5489a83a0cSDaniel Axtens 	entry_flush = entry_flush_orig;
5589a83a0cSDaniel Axtens 
563a72c94eSRussell Currey 	fd = perf_event_open_counter(PERF_TYPE_HW_CACHE, PERF_L1D_READ_MISS_CONFIG, -1);
5789a83a0cSDaniel Axtens 	FAIL_IF(fd < 0);
5889a83a0cSDaniel Axtens 
5989a83a0cSDaniel Axtens 	p = (char *)memalign(zero_size, CACHELINE_SIZE);
6089a83a0cSDaniel Axtens 
6189a83a0cSDaniel Axtens 	FAIL_IF(perf_event_enable(fd));
6289a83a0cSDaniel Axtens 
6389a83a0cSDaniel Axtens 	// disable L1 prefetching
6489a83a0cSDaniel Axtens 	set_dscr(1);
6589a83a0cSDaniel Axtens 
6689a83a0cSDaniel Axtens 	iter = repetitions;
6789a83a0cSDaniel Axtens 
6889a83a0cSDaniel Axtens 	/*
6989a83a0cSDaniel Axtens 	 * We expect to see l1d miss for each cacheline access when entry_flush
7089a83a0cSDaniel Axtens 	 * is set. Allow a small variation on this.
7189a83a0cSDaniel Axtens 	 */
7289a83a0cSDaniel Axtens 	l1d_misses_expected = iterations * (zero_size / CACHELINE_SIZE - 2);
7389a83a0cSDaniel Axtens 
7489a83a0cSDaniel Axtens again:
7589a83a0cSDaniel Axtens 	FAIL_IF(perf_event_reset(fd));
7689a83a0cSDaniel Axtens 
7789a83a0cSDaniel Axtens 	syscall_loop(p, iterations, zero_size);
7889a83a0cSDaniel Axtens 
7989a83a0cSDaniel Axtens 	FAIL_IF(read(fd, &v, sizeof(v)) != sizeof(v));
8089a83a0cSDaniel Axtens 
8189a83a0cSDaniel Axtens 	if (entry_flush && v.l1d_misses >= l1d_misses_expected)
8289a83a0cSDaniel Axtens 		passes++;
8389a83a0cSDaniel Axtens 	else if (!entry_flush && v.l1d_misses < (l1d_misses_expected / 2))
8489a83a0cSDaniel Axtens 		passes++;
8589a83a0cSDaniel Axtens 
8689a83a0cSDaniel Axtens 	l1d_misses_total += v.l1d_misses;
8789a83a0cSDaniel Axtens 
8889a83a0cSDaniel Axtens 	while (--iter)
8989a83a0cSDaniel Axtens 		goto again;
9089a83a0cSDaniel Axtens 
9189a83a0cSDaniel Axtens 	if (passes < repetitions) {
9289a83a0cSDaniel Axtens 		printf("FAIL (L1D misses with entry_flush=%d: %llu %c %lu) [%d/%d failures]\n",
9389a83a0cSDaniel Axtens 		       entry_flush, l1d_misses_total, entry_flush ? '<' : '>',
9489a83a0cSDaniel Axtens 		       entry_flush ? repetitions * l1d_misses_expected :
9589a83a0cSDaniel Axtens 		       repetitions * l1d_misses_expected / 2,
9689a83a0cSDaniel Axtens 		       repetitions - passes, repetitions);
9789a83a0cSDaniel Axtens 		rc = 1;
9889a83a0cSDaniel Axtens 	} else {
9989a83a0cSDaniel Axtens 		printf("PASS (L1D misses with entry_flush=%d: %llu %c %lu) [%d/%d pass]\n",
10089a83a0cSDaniel Axtens 		       entry_flush, l1d_misses_total, entry_flush ? '>' : '<',
10189a83a0cSDaniel Axtens 		       entry_flush ? repetitions * l1d_misses_expected :
10289a83a0cSDaniel Axtens 		       repetitions * l1d_misses_expected / 2,
10389a83a0cSDaniel Axtens 		       passes, repetitions);
10489a83a0cSDaniel Axtens 	}
10589a83a0cSDaniel Axtens 
10689a83a0cSDaniel Axtens 	if (entry_flush == entry_flush_orig) {
10789a83a0cSDaniel Axtens 		entry_flush = !entry_flush_orig;
108*121d340bSBenjamin Gray 		if (write_debugfs_int("powerpc/entry_flush", entry_flush) < 0) {
10989a83a0cSDaniel Axtens 			perror("error writing to powerpc/entry_flush debugfs file");
11089a83a0cSDaniel Axtens 			return 1;
11189a83a0cSDaniel Axtens 		}
11289a83a0cSDaniel Axtens 		iter = repetitions;
11389a83a0cSDaniel Axtens 		l1d_misses_total = 0;
11489a83a0cSDaniel Axtens 		passes = 0;
11589a83a0cSDaniel Axtens 		goto again;
11689a83a0cSDaniel Axtens 	}
11789a83a0cSDaniel Axtens 
11889a83a0cSDaniel Axtens 	perf_event_disable(fd);
11989a83a0cSDaniel Axtens 	close(fd);
12089a83a0cSDaniel Axtens 
12189a83a0cSDaniel Axtens 	set_dscr(0);
12289a83a0cSDaniel Axtens 
123*121d340bSBenjamin Gray 	if (write_debugfs_int("powerpc/rfi_flush", rfi_flush_orig) < 0) {
12489a83a0cSDaniel Axtens 		perror("unable to restore original value of powerpc/rfi_flush debugfs file");
12589a83a0cSDaniel Axtens 		return 1;
12689a83a0cSDaniel Axtens 	}
12789a83a0cSDaniel Axtens 
128*121d340bSBenjamin Gray 	if (write_debugfs_int("powerpc/entry_flush", entry_flush_orig) < 0) {
12989a83a0cSDaniel Axtens 		perror("unable to restore original value of powerpc/entry_flush debugfs file");
13089a83a0cSDaniel Axtens 		return 1;
13189a83a0cSDaniel Axtens 	}
13289a83a0cSDaniel Axtens 
13389a83a0cSDaniel Axtens 	return rc;
13489a83a0cSDaniel Axtens }
13589a83a0cSDaniel Axtens 
main(int argc,char * argv[])13689a83a0cSDaniel Axtens int main(int argc, char *argv[])
13789a83a0cSDaniel Axtens {
13889a83a0cSDaniel Axtens 	return test_harness(entry_flush_test, "entry_flush_test");
13989a83a0cSDaniel Axtens }
140