xref: /linux/drivers/md/dm-vdo/cpu.h (revision e6a901a00822659181c93c86d8bbc2a17779fddc)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright 2023 Red Hat
4  */
5 
6 #ifndef UDS_CPU_H
7 #define UDS_CPU_H
8 
9 #include <linux/cache.h>
10 
11 /**
12  * uds_prefetch_address() - Minimize cache-miss latency by attempting to move data into a CPU cache
13  *                          before it is accessed.
14  *
15  * @address: the address to fetch (may be invalid)
16  * @for_write: must be constant at compile time--false if for reading, true if for writing
17  */
18 static inline void uds_prefetch_address(const void *address, bool for_write)
19 {
20 	/*
21 	 * for_write won't be a constant if we are compiled with optimization turned off, in which
22 	 * case prefetching really doesn't matter. clang can't figure out that if for_write is a
23 	 * constant, it can be passed as the second, mandatorily constant argument to prefetch(),
24 	 * at least currently on llvm 12.
25 	 */
26 	if (__builtin_constant_p(for_write)) {
27 		if (for_write)
28 			__builtin_prefetch(address, true);
29 		else
30 			__builtin_prefetch(address, false);
31 	}
32 }
33 
34 /**
35  * uds_prefetch_range() - Minimize cache-miss latency by attempting to move a range of addresses
36  *                        into a CPU cache before they are accessed.
37  *
38  * @start: the starting address to fetch (may be invalid)
39  * @size: the number of bytes in the address range
40  * @for_write: must be constant at compile time--false if for reading, true if for writing
41  */
42 static inline void uds_prefetch_range(const void *start, unsigned int size,
43 				      bool for_write)
44 {
45 	/*
46 	 * Count the number of cache lines to fetch, allowing for the address range to span an
47 	 * extra cache line boundary due to address alignment.
48 	 */
49 	const char *address = (const char *) start;
50 	unsigned int offset = ((uintptr_t) address % L1_CACHE_BYTES);
51 	unsigned int cache_lines = (1 + ((size + offset) / L1_CACHE_BYTES));
52 
53 	while (cache_lines-- > 0) {
54 		uds_prefetch_address(address, for_write);
55 		address += L1_CACHE_BYTES;
56 	}
57 }
58 
59 #endif /* UDS_CPU_H */
60