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