#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/systimer.h>
#include <sys/globaldata.h>
#include <machine/clock.h>
#include <machine/cputypes.h>
static sysclock_t tsc_cputimer_count_mfence(void);
static sysclock_t tsc_cputimer_count_lfence(void);
static void tsc_cputimer_construct(struct cputimer *, sysclock_t);
static struct cputimer tsc_cputimer = {
.next = SLIST_ENTRY_INITIALIZER,
.name = "TSC",
.pri = CPUTIMER_PRI_TSC,
.type = CPUTIMER_TSC,
.count = NULL,
.fromhz = cputimer_default_fromhz,
.fromus = cputimer_default_fromus,
.construct = tsc_cputimer_construct,
.destruct = cputimer_default_destruct,
.freq = 0
};
static struct cpucounter tsc_cpucounter = {
.freq = 0,
.count = NULL,
.flags = 0,
.prio = CPUCOUNTER_PRIO_TSC,
.type = CPUCOUNTER_TSC
};
static void
tsc_cputimer_construct(struct cputimer *timer, sysclock_t oldclock)
{
timer->base = 0;
timer->base = oldclock - timer->count();
}
static __inline sysclock_t
tsc_cputimer_count(void)
{
uint64_t tsc;
tsc = rdtsc();
return (tsc + tsc_cputimer.base);
}
static sysclock_t
tsc_cputimer_count_lfence(void)
{
cpu_lfence();
return tsc_cputimer_count();
}
static sysclock_t
tsc_cputimer_count_mfence(void)
{
cpu_mfence();
return tsc_cputimer_count();
}
static uint64_t
tsc_cpucounter_count_lfence(void)
{
cpu_lfence();
return (rdtsc());
}
static uint64_t
tsc_cpucounter_count_mfence(void)
{
cpu_mfence();
return (rdtsc());
}
static void
tsc_cputimer_register(void)
{
uint64_t freq;
int enable = 1;
if (!tsc_mpsync) {
#ifndef _KERNEL_VIRTUAL
if (tsc_invariant) {
goto regcnt;
}
#endif
return;
}
TUNABLE_INT_FETCH("hw.tsc_cputimer_enable", &enable);
if (!enable)
return;
freq = tsc_frequency;
tsc_cputimer.freq = freq;
kprintf("TSC: cputimer freq %ju\n", (uintmax_t)freq);
if (cpu_vendor_id == CPU_VENDOR_INTEL)
tsc_cputimer.count = tsc_cputimer_count_lfence;
else
tsc_cputimer.count = tsc_cputimer_count_mfence;
cputimer_register(&tsc_cputimer);
cputimer_select(&tsc_cputimer, 0);
tsc_cpucounter.flags |= CPUCOUNTER_FLAG_MPSYNC;
#ifndef _KERNEL_VIRTUAL
regcnt:
#endif
tsc_cpucounter.freq = tsc_frequency;
if (cpu_vendor_id == CPU_VENDOR_INTEL) {
tsc_cpucounter.count =
tsc_cpucounter_count_lfence;
} else {
tsc_cpucounter.count =
tsc_cpucounter_count_mfence;
}
cpucounter_register(&tsc_cpucounter);
}
SYSINIT(tsc_cputimer_reg, SI_BOOT2_POST_SMP, SI_ORDER_FIRST,
tsc_cputimer_register, NULL);