xref: /dflybsd-src/sys/cpu/x86_64/misc/cputimer_tsc.c (revision 8fbc264d2bc2add66aefe4f4a7966c4364da1211)
17b21e5e4SImre Vadász /*-
27b21e5e4SImre Vadász  * Copyright (c) 1990 The Regents of the University of California.
37b21e5e4SImre Vadász  * Copyright (c) 2008 The DragonFly Project.
47b21e5e4SImre Vadász  * All rights reserved.
57b21e5e4SImre Vadász  *
67b21e5e4SImre Vadász  * This code is derived from software contributed to Berkeley by
77b21e5e4SImre Vadász  * William Jolitz and Don Ahn.
87b21e5e4SImre Vadász  *
97b21e5e4SImre Vadász  * Redistribution and use in source and binary forms, with or without
107b21e5e4SImre Vadász  * modification, are permitted provided that the following conditions
117b21e5e4SImre Vadász  * are met:
127b21e5e4SImre Vadász  * 1. Redistributions of source code must retain the above copyright
137b21e5e4SImre Vadász  *    notice, this list of conditions and the following disclaimer.
147b21e5e4SImre Vadász  * 2. Redistributions in binary form must reproduce the above copyright
157b21e5e4SImre Vadász  *    notice, this list of conditions and the following disclaimer in the
167b21e5e4SImre Vadász  *    documentation and/or other materials provided with the distribution.
177b21e5e4SImre Vadász  * 3. Neither the name of the University nor the names of its contributors
187b21e5e4SImre Vadász  *    may be used to endorse or promote products derived from this software
197b21e5e4SImre Vadász  *    without specific prior written permission.
207b21e5e4SImre Vadász  *
217b21e5e4SImre Vadász  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
227b21e5e4SImre Vadász  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
237b21e5e4SImre Vadász  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
247b21e5e4SImre Vadász  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
257b21e5e4SImre Vadász  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
267b21e5e4SImre Vadász  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
277b21e5e4SImre Vadász  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
287b21e5e4SImre Vadász  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
297b21e5e4SImre Vadász  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
307b21e5e4SImre Vadász  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
317b21e5e4SImre Vadász  * SUCH DAMAGE.
327b21e5e4SImre Vadász  *
337b21e5e4SImre Vadász  *	from: @(#)clock.c	7.2 (Berkeley) 5/12/91
347b21e5e4SImre Vadász  * $FreeBSD: src/sys/i386/isa/clock.c,v 1.149.2.6 2002/11/02 04:41:50 iwasaki Exp $
357b21e5e4SImre Vadász  */
367b21e5e4SImre Vadász 
377b21e5e4SImre Vadász /*
387b21e5e4SImre Vadász  * TSC cputimer.
397b21e5e4SImre Vadász  */
407b21e5e4SImre Vadász 
417b21e5e4SImre Vadász #include <sys/param.h>
427b21e5e4SImre Vadász #include <sys/systm.h>
437b21e5e4SImre Vadász #include <sys/kernel.h>
447b21e5e4SImre Vadász #include <sys/sysctl.h>
457b21e5e4SImre Vadász #include <sys/systimer.h>
467b21e5e4SImre Vadász #include <sys/globaldata.h>
477b21e5e4SImre Vadász 
487b21e5e4SImre Vadász #include <machine/clock.h>
497b21e5e4SImre Vadász #include <machine/cputypes.h>
507b21e5e4SImre Vadász 
517b21e5e4SImre Vadász static sysclock_t tsc_cputimer_count_mfence(void);
527b21e5e4SImre Vadász static sysclock_t tsc_cputimer_count_lfence(void);
537b21e5e4SImre Vadász static void tsc_cputimer_construct(struct cputimer *, sysclock_t);
547b21e5e4SImre Vadász 
557b21e5e4SImre Vadász static struct cputimer	tsc_cputimer = {
567b21e5e4SImre Vadász     .next		= SLIST_ENTRY_INITIALIZER,
577b21e5e4SImre Vadász     .name		= "TSC",
587b21e5e4SImre Vadász     .pri		= CPUTIMER_PRI_TSC,
597b21e5e4SImre Vadász     .type		= CPUTIMER_TSC,
607b21e5e4SImre Vadász     .count		= NULL,	/* determined later */
617b21e5e4SImre Vadász     .fromhz		= cputimer_default_fromhz,
627b21e5e4SImre Vadász     .fromus		= cputimer_default_fromus,
637b21e5e4SImre Vadász     .construct		= tsc_cputimer_construct,
647b21e5e4SImre Vadász     .destruct		= cputimer_default_destruct,
657b21e5e4SImre Vadász     .freq		= 0	/* determined later */
667b21e5e4SImre Vadász };
677b21e5e4SImre Vadász 
687b21e5e4SImre Vadász static struct cpucounter tsc_cpucounter = {
697b21e5e4SImre Vadász     .freq		= 0,	/* determined later */
707b21e5e4SImre Vadász     .count		= NULL,	/* determined later */
717b21e5e4SImre Vadász     .flags		= 0,	/* adjusted later */
727b21e5e4SImre Vadász     .prio		= CPUCOUNTER_PRIO_TSC,
737b21e5e4SImre Vadász     .type		= CPUCOUNTER_TSC
747b21e5e4SImre Vadász };
757b21e5e4SImre Vadász 
767b21e5e4SImre Vadász static void
tsc_cputimer_construct(struct cputimer * timer,sysclock_t oldclock)777b21e5e4SImre Vadász tsc_cputimer_construct(struct cputimer *timer, sysclock_t oldclock)
787b21e5e4SImre Vadász {
797b21e5e4SImre Vadász 	timer->base = 0;
807b21e5e4SImre Vadász 	timer->base = oldclock - timer->count();
817b21e5e4SImre Vadász }
827b21e5e4SImre Vadász 
837b21e5e4SImre Vadász static __inline sysclock_t
tsc_cputimer_count(void)847b21e5e4SImre Vadász tsc_cputimer_count(void)
857b21e5e4SImre Vadász {
867b21e5e4SImre Vadász 	uint64_t tsc;
877b21e5e4SImre Vadász 
887b21e5e4SImre Vadász 	tsc = rdtsc();
897b21e5e4SImre Vadász 
907b21e5e4SImre Vadász 	return (tsc + tsc_cputimer.base);
917b21e5e4SImre Vadász }
927b21e5e4SImre Vadász 
937b21e5e4SImre Vadász static sysclock_t
tsc_cputimer_count_lfence(void)947b21e5e4SImre Vadász tsc_cputimer_count_lfence(void)
957b21e5e4SImre Vadász {
967b21e5e4SImre Vadász 	cpu_lfence();
977b21e5e4SImre Vadász 	return tsc_cputimer_count();
987b21e5e4SImre Vadász }
997b21e5e4SImre Vadász 
1007b21e5e4SImre Vadász static sysclock_t
tsc_cputimer_count_mfence(void)1017b21e5e4SImre Vadász tsc_cputimer_count_mfence(void)
1027b21e5e4SImre Vadász {
1037b21e5e4SImre Vadász 	cpu_mfence();
1047b21e5e4SImre Vadász 	return tsc_cputimer_count();
1057b21e5e4SImre Vadász }
1067b21e5e4SImre Vadász 
1077b21e5e4SImre Vadász static uint64_t
tsc_cpucounter_count_lfence(void)1087b21e5e4SImre Vadász tsc_cpucounter_count_lfence(void)
1097b21e5e4SImre Vadász {
1107b21e5e4SImre Vadász 	cpu_lfence();
1117b21e5e4SImre Vadász 	return (rdtsc());
1127b21e5e4SImre Vadász }
1137b21e5e4SImre Vadász 
1147b21e5e4SImre Vadász static uint64_t
tsc_cpucounter_count_mfence(void)1157b21e5e4SImre Vadász tsc_cpucounter_count_mfence(void)
1167b21e5e4SImre Vadász {
1177b21e5e4SImre Vadász 	cpu_mfence();
1187b21e5e4SImre Vadász 	return (rdtsc());
1197b21e5e4SImre Vadász }
1207b21e5e4SImre Vadász 
1217b21e5e4SImre Vadász static void
tsc_cputimer_register(void)1227b21e5e4SImre Vadász tsc_cputimer_register(void)
1237b21e5e4SImre Vadász {
1247b21e5e4SImre Vadász 	uint64_t freq;
1257b21e5e4SImre Vadász 	int enable = 1;
1267b21e5e4SImre Vadász 
1277b21e5e4SImre Vadász 	if (!tsc_mpsync) {
1287b21e5e4SImre Vadász #ifndef _KERNEL_VIRTUAL
1297b21e5e4SImre Vadász 		if (tsc_invariant) {
1307b21e5e4SImre Vadász 			/* Per-cpu cpucounter still works. */
1317b21e5e4SImre Vadász 			goto regcnt;
1327b21e5e4SImre Vadász 		}
1337b21e5e4SImre Vadász #endif
1347b21e5e4SImre Vadász 		return;
1357b21e5e4SImre Vadász 	}
1367b21e5e4SImre Vadász 
1377b21e5e4SImre Vadász 	TUNABLE_INT_FETCH("hw.tsc_cputimer_enable", &enable);
1387b21e5e4SImre Vadász 	if (!enable)
1397b21e5e4SImre Vadász 		return;
1407b21e5e4SImre Vadász 
141*8fbc264dSMatthew Dillon 	/*
142*8fbc264dSMatthew Dillon 	 * NOTE: We no longer shift the tsc to limit the reported
143*8fbc264dSMatthew Dillon 	 *	 frequency.  We use the actual tsc frequency as-is.
144*8fbc264dSMatthew Dillon 	 */
1457b21e5e4SImre Vadász 	freq = tsc_frequency;
1467b21e5e4SImre Vadász 	tsc_cputimer.freq = freq;
1477b21e5e4SImre Vadász 
148*8fbc264dSMatthew Dillon 	kprintf("TSC: cputimer freq %ju\n", (uintmax_t)freq);
149*8fbc264dSMatthew Dillon 
1507b21e5e4SImre Vadász 	if (cpu_vendor_id == CPU_VENDOR_INTEL)
1517b21e5e4SImre Vadász 		tsc_cputimer.count = tsc_cputimer_count_lfence;
1527b21e5e4SImre Vadász 	else
1537b21e5e4SImre Vadász 		tsc_cputimer.count = tsc_cputimer_count_mfence; /* safe bet */
1547b21e5e4SImre Vadász 
1557b21e5e4SImre Vadász 	cputimer_register(&tsc_cputimer);
1567b21e5e4SImre Vadász 	cputimer_select(&tsc_cputimer, 0);
1577b21e5e4SImre Vadász 
1587b21e5e4SImre Vadász 	tsc_cpucounter.flags |= CPUCOUNTER_FLAG_MPSYNC;
1597b21e5e4SImre Vadász #ifndef _KERNEL_VIRTUAL
1607b21e5e4SImre Vadász regcnt:
1617b21e5e4SImre Vadász #endif
1627b21e5e4SImre Vadász 	tsc_cpucounter.freq = tsc_frequency;
1637b21e5e4SImre Vadász 	if (cpu_vendor_id == CPU_VENDOR_INTEL) {
1647b21e5e4SImre Vadász 		tsc_cpucounter.count =
1657b21e5e4SImre Vadász 		    tsc_cpucounter_count_lfence;
1667b21e5e4SImre Vadász 	} else {
1677b21e5e4SImre Vadász 		tsc_cpucounter.count =
1687b21e5e4SImre Vadász 		    tsc_cpucounter_count_mfence; /* safe bet */
1697b21e5e4SImre Vadász 	}
1707b21e5e4SImre Vadász 	cpucounter_register(&tsc_cpucounter);
1717b21e5e4SImre Vadász }
1727b21e5e4SImre Vadász SYSINIT(tsc_cputimer_reg, SI_BOOT2_POST_SMP, SI_ORDER_FIRST,
1737b21e5e4SImre Vadász 	tsc_cputimer_register, NULL);
174