1 /* SPDX-License-Identifier: GPL-2.0-only */
2 #ifndef X86_TSC_H
3 #define X86_TSC_H
4
5 #include <asm/alternative.h>
6
rdtsc(void)7 static inline uint64_t rdtsc(void)
8 {
9 uint64_t low, high;
10
11 asm volatile ( "rdtsc" : "=a" (low), "=d" (high) );
12
13 return (high << 32) | low;
14 }
15
rdtsc_ordered(void)16 static inline uint64_t rdtsc_ordered(void)
17 {
18 uint64_t low, high, aux;
19
20 /*
21 * The RDTSC instruction is not serializing. Make it dispatch serializing
22 * for the purposes here by issuing LFENCE (or MFENCE if necessary) ahead
23 * of it.
24 *
25 * RDTSCP, otoh, "does wait until all previous instructions have executed
26 * and all previous loads are globally visible" (SDM) / "forces all older
27 * instructions to retire before reading the timestamp counter" (APM).
28 */
29 alternative_io_2("lfence; rdtsc",
30 "mfence; rdtsc", X86_FEATURE_MFENCE_RDTSC,
31 "rdtscp", X86_FEATURE_RDTSCP,
32 ASM_OUTPUT2("=a" (low), "=d" (high), "=c" (aux)),
33 /* no inputs */);
34
35 return (high << 32) | low;
36 }
37
38 #define __write_tsc(val) wrmsrl(MSR_IA32_TSC, val)
39
40 /*
41 * Reliable TSCs are in lockstep across all CPUs. We should never write to
42 * them.
43 */
44 #define write_tsc(val) ({ \
45 ASSERT(!boot_cpu_has(X86_FEATURE_TSC_RELIABLE)); \
46 __write_tsc(val); \
47 })
48
49 #endif /* X86_TSC_H */
50