-/* $OpenBSD: tsc.c,v 1.28 2022/09/18 20:38:50 cheloha Exp $ */
+/* $OpenBSD: tsc.c,v 1.29 2022/09/22 04:57:08 robert Exp $ */
/*
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* Copyright (c) 2016,2017 Reyk Floeter <reyk@openbsd.org>
uint64_t tsc_frequency;
int tsc_is_invariant;
-u_int tsc_get_timecount(struct timecounter *tc);
+u_int tsc_get_timecount_lfence(struct timecounter *tc);
+u_int tsc_get_timecount_rdtscp(struct timecounter *tc);
void tsc_delay(int usecs);
#include "lapic.h"
extern u_int32_t lapic_per_second;
#endif
+u_int64_t (*tsc_rdtsc)(void) = rdtsc_lfence;
+
struct timecounter tsc_timecounter = {
- .tc_get_timecount = tsc_get_timecount,
+ .tc_get_timecount = tsc_get_timecount_lfence,
.tc_poll_pps = NULL,
.tc_counter_mask = ~0u,
.tc_frequency = 0,
.tc_name = "tsc",
.tc_quality = -1000,
.tc_priv = NULL,
- .tc_user = TC_TSC,
+ .tc_user = TC_TSC_LFENCE,
};
uint64_t
!(ci->ci_flags & CPUF_INVAR_TSC))
return;
+ /* Prefer RDTSCP where supported. */
+ if (ISSET(ci->ci_feature_eflags, CPUID_RDTSCP)) {
+ tsc_rdtsc = rdtscp;
+ tsc_timecounter.tc_get_timecount = tsc_get_timecount_rdtscp;
+ tsc_timecounter.tc_user = TC_TSC_RDTSCP;
+ }
+
tsc_is_invariant = 1;
tsc_frequency = tsc_freq_cpuid(ci);
int i;
for (i = 0; i < RECALIBRATE_MAX_RETRIES; i++) {
- tsc1 = rdtsc_lfence();
+ tsc1 = tsc_rdtsc();
n = (tc->tc_get_timecount(tc) & tc->tc_counter_mask);
- tsc2 = rdtsc_lfence();
+ tsc2 = tsc_rdtsc();
if ((tsc2 - tsc1) < RECALIBRATE_SMI_THRESHOLD) {
*count = n;
}
u_int
-tsc_get_timecount(struct timecounter *tc)
+tsc_get_timecount_lfence(struct timecounter *tc)
{
return rdtsc_lfence();
}
+u_int
+tsc_get_timecount_rdtscp(struct timecounter *tc)
+{
+ return rdtscp();
+}
+
void
tsc_timecounter_init(struct cpu_info *ci, uint64_t cpufreq)
{
uint64_t interval, start;
interval = (uint64_t)usecs * tsc_frequency / 1000000;
- start = rdtsc_lfence();
- while (rdtsc_lfence() - start < interval)
+ start = tsc_rdtsc();
+ while (tsc_rdtsc() - start < interval)
CPU_BUSY_CYCLE();
}
{
uint64_t ap_val, bp_val, end, lag;
- ap_val = rdtsc_lfence();
+ ap_val = tsc_rdtsc();
end = ap_val + tsc_test_cycles;
while (__predict_true(ap_val < end)) {
/*
* the BP and the counters cannot be synchronized.
*/
bp_val = tsc_bp_status.val;
- ap_val = rdtsc_lfence();
+ ap_val = tsc_rdtsc();
tsc_ap_status.val = ap_val;
/*
{
uint64_t ap_val, bp_val, end, lag;
- bp_val = rdtsc_lfence();
+ bp_val = tsc_rdtsc();
end = bp_val + tsc_test_cycles;
while (__predict_true(bp_val < end)) {
ap_val = tsc_ap_status.val;
- bp_val = rdtsc_lfence();
+ bp_val = tsc_rdtsc();
tsc_bp_status.val = bp_val;
if (__predict_false(bp_val < ap_val)) {