2 * Copyright (c) 2012 NetApp, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/types.h>
33 #include <sys/sysctl.h>
35 #include <machine/cpufunc.h>
46 * The ACPI Power Management timer is a free-running 24- or 32-bit
47 * timer with a frequency of 3.579545MHz
49 * This implementation will be 32-bits
52 #define IO_PMTMR 0x408 /* 4-byte i/o port for the timer */
54 #define PMTMR_FREQ 3579545 /* 3.579545MHz */
56 static pthread_mutex_t pmtmr_mtx;
58 static uint64_t pmtmr_old;
60 static uint64_t pmtmr_tscf;
61 static uint64_t pmtmr_tsc_old;
63 static clockid_t clockid = CLOCK_UPTIME_FAST;
64 static struct timespec pmtmr_uptime_old;
66 #define timespecsub(vvp, uvp) \
68 (vvp)->tv_sec -= (uvp)->tv_sec; \
69 (vvp)->tv_nsec -= (uvp)->tv_nsec; \
70 if ((vvp)->tv_nsec < 0) { \
72 (vvp)->tv_nsec += 1000000000; \
77 timespec_to_pmtmr(const struct timespec *tsnew, const struct timespec *tsold)
79 struct timespec tsdiff;
83 timespecsub(&tsdiff, tsold);
84 nsecs = tsdiff.tv_sec * 1000000000 + tsdiff.tv_nsec;
87 return (nsecs * PMTMR_FREQ / 1000000000 + pmtmr_old);
91 tsc_to_pmtmr(uint64_t tsc_new, uint64_t tsc_old)
94 return ((tsc_new - tsc_old) * PMTMR_FREQ / pmtmr_tscf + pmtmr_old);
102 struct timespec tsnew, tsold = { 0 };
104 len = sizeof(smp_tsc);
105 err = sysctlbyname("kern.timecounter.smp_tsc", &smp_tsc, &len, NULL, 0);
109 len = sizeof(pmtmr_tscf);
110 err = sysctlbyname("machdep.tsc_freq", &pmtmr_tscf, &len,
114 pmtmr_tsc_old = rdtsc();
115 pmtmr_old = tsc_to_pmtmr(pmtmr_tsc_old, 0);
117 if (getenv("BHYVE_PMTMR_PRECISE") != NULL)
118 clockid = CLOCK_UPTIME;
120 err = clock_gettime(clockid, &tsnew);
123 pmtmr_uptime_old = tsnew;
124 pmtmr_old = timespec_to_pmtmr(&tsnew, &tsold);
131 struct timespec tsnew;
132 uint64_t pmtmr_tsc_new;
136 static int inited = 0;
139 pthread_mutex_init(&pmtmr_mtx, NULL);
144 pthread_mutex_lock(&pmtmr_mtx);
147 pmtmr_tsc_new = rdtsc();
148 pmtmr_new = tsc_to_pmtmr(pmtmr_tsc_new, pmtmr_tsc_old);
149 pmtmr_tsc_old = pmtmr_tsc_new;
151 error = clock_gettime(clockid, &tsnew);
154 pmtmr_new = timespec_to_pmtmr(&tsnew, &pmtmr_uptime_old);
155 pmtmr_uptime_old = tsnew;
157 pmtmr_old = pmtmr_new;
159 pthread_mutex_unlock(&pmtmr_mtx);
165 pmtmr_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
166 uint32_t *eax, void *arg)
178 INOUT_PORT(pmtmr, IO_PMTMR, IOPORT_F_IN, pmtmr_handler);