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