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 */
uds_prefetch_address(const void * address,bool for_write)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 */
uds_prefetch_range(const void * start,unsigned int size,bool for_write)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