xref: /freebsd/sys/kern/kern_tc.c (revision c3aac50f284c6cca5b4f2eb46aaa13812cb8b630)
1df8bae1dSRodney W. Grimes /*-
27ec73f64SPoul-Henning Kamp  * Copyright (c) 1997, 1998 Poul-Henning Kamp <phk@FreeBSD.org>
3df8bae1dSRodney W. Grimes  * Copyright (c) 1982, 1986, 1991, 1993
4df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
5df8bae1dSRodney W. Grimes  * (c) UNIX System Laboratories, Inc.
6df8bae1dSRodney W. Grimes  * All or some portions of this file are derived from material licensed
7df8bae1dSRodney W. Grimes  * to the University of California by American Telephone and Telegraph
8df8bae1dSRodney W. Grimes  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
9df8bae1dSRodney W. Grimes  * the permission of UNIX System Laboratories, Inc.
10df8bae1dSRodney W. Grimes  *
11df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
12df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
13df8bae1dSRodney W. Grimes  * are met:
14df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
15df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
16df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
17df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
18df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
19df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
20df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
21df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
22df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
23df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
24df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
25df8bae1dSRodney W. Grimes  *    without specific prior written permission.
26df8bae1dSRodney W. Grimes  *
27df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
38df8bae1dSRodney W. Grimes  *
39df8bae1dSRodney W. Grimes  *	@(#)kern_clock.c	8.5 (Berkeley) 1/21/94
40c3aac50fSPeter Wemm  * $FreeBSD$
41df8bae1dSRodney W. Grimes  */
42df8bae1dSRodney W. Grimes 
4332c20357SPoul-Henning Kamp #include "opt_ntp.h"
4432c20357SPoul-Henning Kamp 
45df8bae1dSRodney W. Grimes #include <sys/param.h>
46df8bae1dSRodney W. Grimes #include <sys/systm.h>
47df8bae1dSRodney W. Grimes #include <sys/dkstat.h>
48df8bae1dSRodney W. Grimes #include <sys/callout.h>
49df8bae1dSRodney W. Grimes #include <sys/kernel.h>
50df8bae1dSRodney W. Grimes #include <sys/proc.h>
513bac064fSPoul-Henning Kamp #include <sys/malloc.h>
52df8bae1dSRodney W. Grimes #include <sys/resourcevar.h>
53797f2d22SPoul-Henning Kamp #include <sys/signalvar.h>
543f31c649SGarrett Wollman #include <sys/timex.h>
5532c20357SPoul-Henning Kamp #include <sys/timepps.h>
568a129caeSDavid Greenman #include <vm/vm.h>
57996c772fSJohn Dyson #include <sys/lock.h>
58efeaf95aSDavid Greenman #include <vm/pmap.h>
59efeaf95aSDavid Greenman #include <vm/vm_map.h>
60797f2d22SPoul-Henning Kamp #include <sys/sysctl.h>
61df8bae1dSRodney W. Grimes 
62df8bae1dSRodney W. Grimes #include <machine/cpu.h>
63b1037dcdSBruce Evans #include <machine/limits.h>
64df8bae1dSRodney W. Grimes 
65df8bae1dSRodney W. Grimes #ifdef GPROF
66df8bae1dSRodney W. Grimes #include <sys/gmon.h>
67df8bae1dSRodney W. Grimes #endif
68df8bae1dSRodney W. Grimes 
69eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK)
70eae8fc2cSSteve Passe #include <machine/smp.h>
71eae8fc2cSSteve Passe #endif
72eae8fc2cSSteve Passe 
733bac064fSPoul-Henning Kamp /*
743bac064fSPoul-Henning Kamp  * Number of timecounters used to implement stable storage
753bac064fSPoul-Henning Kamp  */
763bac064fSPoul-Henning Kamp #ifndef NTIMECOUNTER
77c2906d55SPoul-Henning Kamp #define NTIMECOUNTER	5
783bac064fSPoul-Henning Kamp #endif
793bac064fSPoul-Henning Kamp 
803bac064fSPoul-Henning Kamp static MALLOC_DEFINE(M_TIMECOUNTER, "timecounter",
813bac064fSPoul-Henning Kamp 	"Timecounter stable storage");
823bac064fSPoul-Henning Kamp 
83d841aaa7SBruce Evans static void initclocks __P((void *dummy));
842b14f991SJulian Elischer SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL)
852b14f991SJulian Elischer 
86c2906d55SPoul-Henning Kamp static void tco_forward __P((int force));
877ec73f64SPoul-Henning Kamp static void tco_setscales __P((struct timecounter *tc));
88a58f0f8eSPoul-Henning Kamp static __inline unsigned tco_delta __P((struct timecounter *tc));
897ec73f64SPoul-Henning Kamp 
90f23b4c91SGarrett Wollman /* Some of these don't belong here, but it's easiest to concentrate them. */
91eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK)
92eae8fc2cSSteve Passe long cp_time[CPUSTATES];
93eae8fc2cSSteve Passe #else
9427a0b398SPoul-Henning Kamp static long cp_time[CPUSTATES];
95eae8fc2cSSteve Passe #endif
96f23b4c91SGarrett Wollman 
97f23b4c91SGarrett Wollman long tk_cancc;
98f23b4c91SGarrett Wollman long tk_nin;
99f23b4c91SGarrett Wollman long tk_nout;
100f23b4c91SGarrett Wollman long tk_rawcc;
101f23b4c91SGarrett Wollman 
102227ee8a1SPoul-Henning Kamp time_t time_second;
103227ee8a1SPoul-Henning Kamp 
104df8bae1dSRodney W. Grimes /*
105510eb5b9SPoul-Henning Kamp  * Which update policy to use.
106510eb5b9SPoul-Henning Kamp  *   0 - every tick, bad hardware may fail with "calcru negative..."
107510eb5b9SPoul-Henning Kamp  *   1 - more resistent to the above hardware, but less efficient.
108510eb5b9SPoul-Henning Kamp  */
109510eb5b9SPoul-Henning Kamp static int tco_method;
110510eb5b9SPoul-Henning Kamp 
111510eb5b9SPoul-Henning Kamp /*
1123bac064fSPoul-Henning Kamp  * Implement a dummy timecounter which we can use until we get a real one
1133bac064fSPoul-Henning Kamp  * in the air.  This allows the console and other early stuff to use
1143bac064fSPoul-Henning Kamp  * timeservices.
1153bac064fSPoul-Henning Kamp  */
1163bac064fSPoul-Henning Kamp 
1173bac064fSPoul-Henning Kamp static unsigned
1183bac064fSPoul-Henning Kamp dummy_get_timecount(struct timecounter *tc)
1193bac064fSPoul-Henning Kamp {
1203bac064fSPoul-Henning Kamp 	static unsigned now;
1213bac064fSPoul-Henning Kamp 	return (++now);
1223bac064fSPoul-Henning Kamp }
1233bac064fSPoul-Henning Kamp 
1243bac064fSPoul-Henning Kamp static struct timecounter dummy_timecounter = {
1253bac064fSPoul-Henning Kamp 	dummy_get_timecount,
1263bac064fSPoul-Henning Kamp 	0,
1273bac064fSPoul-Henning Kamp 	~0u,
1283bac064fSPoul-Henning Kamp 	1000000,
1293bac064fSPoul-Henning Kamp 	"dummy"
1303bac064fSPoul-Henning Kamp };
1313bac064fSPoul-Henning Kamp 
1323bac064fSPoul-Henning Kamp struct timecounter *timecounter = &dummy_timecounter;
1333bac064fSPoul-Henning Kamp 
1343bac064fSPoul-Henning Kamp /*
135df8bae1dSRodney W. Grimes  * Clock handling routines.
136df8bae1dSRodney W. Grimes  *
137b05dcf3cSPoul-Henning Kamp  * This code is written to operate with two timers that run independently of
138b05dcf3cSPoul-Henning Kamp  * each other.
1397ec73f64SPoul-Henning Kamp  *
140b05dcf3cSPoul-Henning Kamp  * The main timer, running hz times per second, is used to trigger interval
141b05dcf3cSPoul-Henning Kamp  * timers, timeouts and rescheduling as needed.
1427ec73f64SPoul-Henning Kamp  *
143b05dcf3cSPoul-Henning Kamp  * The second timer handles kernel and user profiling,
144b05dcf3cSPoul-Henning Kamp  * and does resource use estimation.  If the second timer is programmable,
145b05dcf3cSPoul-Henning Kamp  * it is randomized to avoid aliasing between the two clocks.  For example,
146b05dcf3cSPoul-Henning Kamp  * the randomization prevents an adversary from always giving up the cpu
147df8bae1dSRodney W. Grimes  * just before its quantum expires.  Otherwise, it would never accumulate
148df8bae1dSRodney W. Grimes  * cpu ticks.  The mean frequency of the second timer is stathz.
149b05dcf3cSPoul-Henning Kamp  *
150b05dcf3cSPoul-Henning Kamp  * If no second timer exists, stathz will be zero; in this case we drive
151b05dcf3cSPoul-Henning Kamp  * profiling and statistics off the main clock.  This WILL NOT be accurate;
152b05dcf3cSPoul-Henning Kamp  * do not do it unless absolutely necessary.
153b05dcf3cSPoul-Henning Kamp  *
154df8bae1dSRodney W. Grimes  * The statistics clock may (or may not) be run at a higher rate while
155b05dcf3cSPoul-Henning Kamp  * profiling.  This profile clock runs at profhz.  We require that profhz
156b05dcf3cSPoul-Henning Kamp  * be an integral multiple of stathz.
157b05dcf3cSPoul-Henning Kamp  *
158b05dcf3cSPoul-Henning Kamp  * If the statistics clock is running fast, it must be divided by the ratio
159b05dcf3cSPoul-Henning Kamp  * profhz/stathz for statistics.  (For profiling, every tick counts.)
160df8bae1dSRodney W. Grimes  *
1617ec73f64SPoul-Henning Kamp  * Time-of-day is maintained using a "timecounter", which may or may
1627ec73f64SPoul-Henning Kamp  * not be related to the hardware generating the above mentioned
1637ec73f64SPoul-Henning Kamp  * interrupts.
164df8bae1dSRodney W. Grimes  */
165df8bae1dSRodney W. Grimes 
166df8bae1dSRodney W. Grimes int	stathz;
167df8bae1dSRodney W. Grimes int	profhz;
168cc3d5226SBruce Evans static int profprocs;
169df8bae1dSRodney W. Grimes int	ticks;
170df8bae1dSRodney W. Grimes static int psdiv, pscnt;		/* prof => stat divider */
171cc3d5226SBruce Evans int	psratio;			/* ratio: prof / stat */
172df8bae1dSRodney W. Grimes 
173df8bae1dSRodney W. Grimes /*
174df8bae1dSRodney W. Grimes  * Initialize clock frequencies and start both clocks running.
175df8bae1dSRodney W. Grimes  */
1762b14f991SJulian Elischer /* ARGSUSED*/
1772b14f991SJulian Elischer static void
178d841aaa7SBruce Evans initclocks(dummy)
179d841aaa7SBruce Evans 	void *dummy;
180df8bae1dSRodney W. Grimes {
181df8bae1dSRodney W. Grimes 	register int i;
182df8bae1dSRodney W. Grimes 
183df8bae1dSRodney W. Grimes 	/*
184df8bae1dSRodney W. Grimes 	 * Set divisors to 1 (normal case) and let the machine-specific
185df8bae1dSRodney W. Grimes 	 * code do its bit.
186df8bae1dSRodney W. Grimes 	 */
187df8bae1dSRodney W. Grimes 	psdiv = pscnt = 1;
188df8bae1dSRodney W. Grimes 	cpu_initclocks();
189df8bae1dSRodney W. Grimes 
190df8bae1dSRodney W. Grimes 	/*
191df8bae1dSRodney W. Grimes 	 * Compute profhz/stathz, and fix profhz if needed.
192df8bae1dSRodney W. Grimes 	 */
193df8bae1dSRodney W. Grimes 	i = stathz ? stathz : hz;
194df8bae1dSRodney W. Grimes 	if (profhz == 0)
195df8bae1dSRodney W. Grimes 		profhz = i;
196df8bae1dSRodney W. Grimes 	psratio = profhz / i;
197df8bae1dSRodney W. Grimes }
198df8bae1dSRodney W. Grimes 
199df8bae1dSRodney W. Grimes /*
200df8bae1dSRodney W. Grimes  * The real-time timer, interrupting hz times per second.
201df8bae1dSRodney W. Grimes  */
202df8bae1dSRodney W. Grimes void
203df8bae1dSRodney W. Grimes hardclock(frame)
204df8bae1dSRodney W. Grimes 	register struct clockframe *frame;
205df8bae1dSRodney W. Grimes {
206df8bae1dSRodney W. Grimes 	register struct proc *p;
207df8bae1dSRodney W. Grimes 
208df8bae1dSRodney W. Grimes 	p = curproc;
209df8bae1dSRodney W. Grimes 	if (p) {
210df8bae1dSRodney W. Grimes 		register struct pstats *pstats;
211df8bae1dSRodney W. Grimes 
212df8bae1dSRodney W. Grimes 		/*
213df8bae1dSRodney W. Grimes 		 * Run current process's virtual and profile time, as needed.
214df8bae1dSRodney W. Grimes 		 */
215df8bae1dSRodney W. Grimes 		pstats = p->p_stats;
216df8bae1dSRodney W. Grimes 		if (CLKF_USERMODE(frame) &&
2174cf41af3SPoul-Henning Kamp 		    timevalisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) &&
218df8bae1dSRodney W. Grimes 		    itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0)
219df8bae1dSRodney W. Grimes 			psignal(p, SIGVTALRM);
2204cf41af3SPoul-Henning Kamp 		if (timevalisset(&pstats->p_timer[ITIMER_PROF].it_value) &&
221df8bae1dSRodney W. Grimes 		    itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0)
222df8bae1dSRodney W. Grimes 			psignal(p, SIGPROF);
223df8bae1dSRodney W. Grimes 	}
224df8bae1dSRodney W. Grimes 
225eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK)
226eae8fc2cSSteve Passe 	forward_hardclock(pscnt);
227eae8fc2cSSteve Passe #endif
228b05dcf3cSPoul-Henning Kamp 
229df8bae1dSRodney W. Grimes 	/*
230df8bae1dSRodney W. Grimes 	 * If no separate statistics clock is available, run it from here.
231df8bae1dSRodney W. Grimes 	 */
232df8bae1dSRodney W. Grimes 	if (stathz == 0)
233df8bae1dSRodney W. Grimes 		statclock(frame);
234df8bae1dSRodney W. Grimes 
235c2906d55SPoul-Henning Kamp 	tco_forward(0);
236df8bae1dSRodney W. Grimes 	ticks++;
2373f31c649SGarrett Wollman 
238b05dcf3cSPoul-Henning Kamp 	/*
239b05dcf3cSPoul-Henning Kamp 	 * Process callouts at a very low cpu priority, so we don't keep the
240b05dcf3cSPoul-Henning Kamp 	 * relatively high clock interrupt priority any longer than necessary.
241b05dcf3cSPoul-Henning Kamp 	 */
242b05dcf3cSPoul-Henning Kamp 	if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) {
243b05dcf3cSPoul-Henning Kamp 		if (CLKF_BASEPRI(frame)) {
244b05dcf3cSPoul-Henning Kamp 			/*
245b05dcf3cSPoul-Henning Kamp 			 * Save the overhead of a software interrupt;
246b05dcf3cSPoul-Henning Kamp 			 * it will happen as soon as we return, so do it now.
247b05dcf3cSPoul-Henning Kamp 			 */
248b05dcf3cSPoul-Henning Kamp 			(void)splsoftclock();
249b05dcf3cSPoul-Henning Kamp 			softclock();
250b05dcf3cSPoul-Henning Kamp 		} else
251eeb355f7SPoul-Henning Kamp 			setsoftclock();
252b05dcf3cSPoul-Henning Kamp 	} else if (softticks + 1 == ticks)
253b05dcf3cSPoul-Henning Kamp 		++softticks;
254ab36c067SJustin T. Gibbs }
255ab36c067SJustin T. Gibbs 
256df8bae1dSRodney W. Grimes /*
257227ee8a1SPoul-Henning Kamp  * Compute number of ticks in the specified amount of time.
258df8bae1dSRodney W. Grimes  */
259df8bae1dSRodney W. Grimes int
260227ee8a1SPoul-Henning Kamp tvtohz(tv)
261df8bae1dSRodney W. Grimes 	struct timeval *tv;
262df8bae1dSRodney W. Grimes {
2636976af69SBruce Evans 	register unsigned long ticks;
2646976af69SBruce Evans 	register long sec, usec;
265df8bae1dSRodney W. Grimes 
266df8bae1dSRodney W. Grimes 	/*
2676976af69SBruce Evans 	 * If the number of usecs in the whole seconds part of the time
2686976af69SBruce Evans 	 * difference fits in a long, then the total number of usecs will
2696976af69SBruce Evans 	 * fit in an unsigned long.  Compute the total and convert it to
2706976af69SBruce Evans 	 * ticks, rounding up and adding 1 to allow for the current tick
2716976af69SBruce Evans 	 * to expire.  Rounding also depends on unsigned long arithmetic
2726976af69SBruce Evans 	 * to avoid overflow.
273df8bae1dSRodney W. Grimes 	 *
2746976af69SBruce Evans 	 * Otherwise, if the number of ticks in the whole seconds part of
2756976af69SBruce Evans 	 * the time difference fits in a long, then convert the parts to
2766976af69SBruce Evans 	 * ticks separately and add, using similar rounding methods and
2776976af69SBruce Evans 	 * overflow avoidance.  This method would work in the previous
2786976af69SBruce Evans 	 * case but it is slightly slower and assumes that hz is integral.
2796976af69SBruce Evans 	 *
2806976af69SBruce Evans 	 * Otherwise, round the time difference down to the maximum
2816976af69SBruce Evans 	 * representable value.
2826976af69SBruce Evans 	 *
2836976af69SBruce Evans 	 * If ints have 32 bits, then the maximum value for any timeout in
2846976af69SBruce Evans 	 * 10ms ticks is 248 days.
285df8bae1dSRodney W. Grimes 	 */
286227ee8a1SPoul-Henning Kamp 	sec = tv->tv_sec;
287227ee8a1SPoul-Henning Kamp 	usec = tv->tv_usec;
2886976af69SBruce Evans 	if (usec < 0) {
2896976af69SBruce Evans 		sec--;
2906976af69SBruce Evans 		usec += 1000000;
2916976af69SBruce Evans 	}
2926976af69SBruce Evans 	if (sec < 0) {
2936976af69SBruce Evans #ifdef DIAGNOSTIC
294b05dcf3cSPoul-Henning Kamp 		if (usec > 0) {
2957ec73f64SPoul-Henning Kamp 			sec++;
2967ec73f64SPoul-Henning Kamp 			usec -= 1000000;
2977ec73f64SPoul-Henning Kamp 		}
298227ee8a1SPoul-Henning Kamp 		printf("tvotohz: negative time difference %ld sec %ld usec\n",
2996976af69SBruce Evans 		       sec, usec);
3006976af69SBruce Evans #endif
3016976af69SBruce Evans 		ticks = 1;
3026976af69SBruce Evans 	} else if (sec <= LONG_MAX / 1000000)
3036976af69SBruce Evans 		ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1))
3046976af69SBruce Evans 			/ tick + 1;
3056976af69SBruce Evans 	else if (sec <= LONG_MAX / hz)
3066976af69SBruce Evans 		ticks = sec * hz
3076976af69SBruce Evans 			+ ((unsigned long)usec + (tick - 1)) / tick + 1;
3086976af69SBruce Evans 	else
3096976af69SBruce Evans 		ticks = LONG_MAX;
3106976af69SBruce Evans 	if (ticks > INT_MAX)
3116976af69SBruce Evans 		ticks = INT_MAX;
312d6116663SAlexander Langer 	return ((int)ticks);
313df8bae1dSRodney W. Grimes }
314df8bae1dSRodney W. Grimes 
315df8bae1dSRodney W. Grimes /*
316df8bae1dSRodney W. Grimes  * Start profiling on a process.
317df8bae1dSRodney W. Grimes  *
318df8bae1dSRodney W. Grimes  * Kernel profiling passes proc0 which never exits and hence
319df8bae1dSRodney W. Grimes  * keeps the profile clock running constantly.
320df8bae1dSRodney W. Grimes  */
321df8bae1dSRodney W. Grimes void
322df8bae1dSRodney W. Grimes startprofclock(p)
323df8bae1dSRodney W. Grimes 	register struct proc *p;
324df8bae1dSRodney W. Grimes {
325df8bae1dSRodney W. Grimes 	int s;
326df8bae1dSRodney W. Grimes 
327df8bae1dSRodney W. Grimes 	if ((p->p_flag & P_PROFIL) == 0) {
328df8bae1dSRodney W. Grimes 		p->p_flag |= P_PROFIL;
329df8bae1dSRodney W. Grimes 		if (++profprocs == 1 && stathz != 0) {
330df8bae1dSRodney W. Grimes 			s = splstatclock();
331df8bae1dSRodney W. Grimes 			psdiv = pscnt = psratio;
332df8bae1dSRodney W. Grimes 			setstatclockrate(profhz);
333df8bae1dSRodney W. Grimes 			splx(s);
334df8bae1dSRodney W. Grimes 		}
335df8bae1dSRodney W. Grimes 	}
336df8bae1dSRodney W. Grimes }
337df8bae1dSRodney W. Grimes 
338df8bae1dSRodney W. Grimes /*
339df8bae1dSRodney W. Grimes  * Stop profiling on a process.
340df8bae1dSRodney W. Grimes  */
341df8bae1dSRodney W. Grimes void
342df8bae1dSRodney W. Grimes stopprofclock(p)
343df8bae1dSRodney W. Grimes 	register struct proc *p;
344df8bae1dSRodney W. Grimes {
345df8bae1dSRodney W. Grimes 	int s;
346df8bae1dSRodney W. Grimes 
347df8bae1dSRodney W. Grimes 	if (p->p_flag & P_PROFIL) {
348df8bae1dSRodney W. Grimes 		p->p_flag &= ~P_PROFIL;
349df8bae1dSRodney W. Grimes 		if (--profprocs == 0 && stathz != 0) {
350df8bae1dSRodney W. Grimes 			s = splstatclock();
351df8bae1dSRodney W. Grimes 			psdiv = pscnt = 1;
352df8bae1dSRodney W. Grimes 			setstatclockrate(stathz);
353df8bae1dSRodney W. Grimes 			splx(s);
354df8bae1dSRodney W. Grimes 		}
355df8bae1dSRodney W. Grimes 	}
356df8bae1dSRodney W. Grimes }
357df8bae1dSRodney W. Grimes 
358df8bae1dSRodney W. Grimes /*
359df8bae1dSRodney W. Grimes  * Statistics clock.  Grab profile sample, and if divider reaches 0,
360df8bae1dSRodney W. Grimes  * do process and kernel statistics.
361df8bae1dSRodney W. Grimes  */
362df8bae1dSRodney W. Grimes void
363df8bae1dSRodney W. Grimes statclock(frame)
364df8bae1dSRodney W. Grimes 	register struct clockframe *frame;
365df8bae1dSRodney W. Grimes {
366df8bae1dSRodney W. Grimes #ifdef GPROF
367df8bae1dSRodney W. Grimes 	register struct gmonparam *g;
368fffd686aSBruce Evans 	int i;
369df8bae1dSRodney W. Grimes #endif
370f5e9e8ecSBruce Evans 	register struct proc *p;
3718a129caeSDavid Greenman 	struct pstats *pstats;
372f5e9e8ecSBruce Evans 	long rss;
3738a129caeSDavid Greenman 	struct rusage *ru;
3748a129caeSDavid Greenman 	struct vmspace *vm;
3758a129caeSDavid Greenman 
3768843cc35SSøren Schmidt 	if (curproc != NULL && CLKF_USERMODE(frame)) {
377f5e9e8ecSBruce Evans 		p = curproc;
378df8bae1dSRodney W. Grimes 		if (p->p_flag & P_PROFIL)
379df8bae1dSRodney W. Grimes 			addupc_intr(p, CLKF_PC(frame), 1);
380eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK)
381eae8fc2cSSteve Passe 		if (stathz != 0)
382eae8fc2cSSteve Passe 			forward_statclock(pscnt);
383eae8fc2cSSteve Passe #endif
384df8bae1dSRodney W. Grimes 		if (--pscnt > 0)
385df8bae1dSRodney W. Grimes 			return;
386df8bae1dSRodney W. Grimes 		/*
387df8bae1dSRodney W. Grimes 		 * Came from user mode; CPU was in user state.
388df8bae1dSRodney W. Grimes 		 * If this process is being profiled record the tick.
389df8bae1dSRodney W. Grimes 		 */
390df8bae1dSRodney W. Grimes 		p->p_uticks++;
391df8bae1dSRodney W. Grimes 		if (p->p_nice > NZERO)
392df8bae1dSRodney W. Grimes 			cp_time[CP_NICE]++;
393df8bae1dSRodney W. Grimes 		else
394df8bae1dSRodney W. Grimes 			cp_time[CP_USER]++;
395df8bae1dSRodney W. Grimes 	} else {
396df8bae1dSRodney W. Grimes #ifdef GPROF
397df8bae1dSRodney W. Grimes 		/*
398df8bae1dSRodney W. Grimes 		 * Kernel statistics are just like addupc_intr, only easier.
399df8bae1dSRodney W. Grimes 		 */
400df8bae1dSRodney W. Grimes 		g = &_gmonparam;
401df8bae1dSRodney W. Grimes 		if (g->state == GMON_PROF_ON) {
402df8bae1dSRodney W. Grimes 			i = CLKF_PC(frame) - g->lowpc;
403df8bae1dSRodney W. Grimes 			if (i < g->textsize) {
404df8bae1dSRodney W. Grimes 				i /= HISTFRACTION * sizeof(*g->kcount);
405df8bae1dSRodney W. Grimes 				g->kcount[i]++;
406df8bae1dSRodney W. Grimes 			}
407df8bae1dSRodney W. Grimes 		}
408df8bae1dSRodney W. Grimes #endif
409eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK)
410eae8fc2cSSteve Passe 		if (stathz != 0)
411eae8fc2cSSteve Passe 			forward_statclock(pscnt);
412eae8fc2cSSteve Passe #endif
413df8bae1dSRodney W. Grimes 		if (--pscnt > 0)
414df8bae1dSRodney W. Grimes 			return;
415df8bae1dSRodney W. Grimes 		/*
416df8bae1dSRodney W. Grimes 		 * Came from kernel mode, so we were:
417df8bae1dSRodney W. Grimes 		 * - handling an interrupt,
418df8bae1dSRodney W. Grimes 		 * - doing syscall or trap work on behalf of the current
419df8bae1dSRodney W. Grimes 		 *   user process, or
420df8bae1dSRodney W. Grimes 		 * - spinning in the idle loop.
421df8bae1dSRodney W. Grimes 		 * Whichever it is, charge the time as appropriate.
422df8bae1dSRodney W. Grimes 		 * Note that we charge interrupts to the current process,
423df8bae1dSRodney W. Grimes 		 * regardless of whether they are ``for'' that process,
424df8bae1dSRodney W. Grimes 		 * so that we know how much of its real time was spent
425df8bae1dSRodney W. Grimes 		 * in ``non-process'' (i.e., interrupt) work.
426df8bae1dSRodney W. Grimes 		 */
427f5e9e8ecSBruce Evans 		p = curproc;
428df8bae1dSRodney W. Grimes 		if (CLKF_INTR(frame)) {
429df8bae1dSRodney W. Grimes 			if (p != NULL)
430df8bae1dSRodney W. Grimes 				p->p_iticks++;
431df8bae1dSRodney W. Grimes 			cp_time[CP_INTR]++;
432b672aa4bSBruce Evans 		} else if (p != NULL) {
433df8bae1dSRodney W. Grimes 			p->p_sticks++;
434df8bae1dSRodney W. Grimes 			cp_time[CP_SYS]++;
435df8bae1dSRodney W. Grimes 		} else
436df8bae1dSRodney W. Grimes 			cp_time[CP_IDLE]++;
437df8bae1dSRodney W. Grimes 	}
438df8bae1dSRodney W. Grimes 	pscnt = psdiv;
439df8bae1dSRodney W. Grimes 
440df8bae1dSRodney W. Grimes 	/*
441df8bae1dSRodney W. Grimes 	 * We maintain statistics shown by user-level statistics
4427ea97031SJustin T. Gibbs 	 * programs:  the amount of time in each cpu state.
443df8bae1dSRodney W. Grimes 	 */
444df8bae1dSRodney W. Grimes 
445df8bae1dSRodney W. Grimes 	/*
446df8bae1dSRodney W. Grimes 	 * We adjust the priority of the current process.  The priority of
447df8bae1dSRodney W. Grimes 	 * a process gets worse as it accumulates CPU time.  The cpu usage
448df8bae1dSRodney W. Grimes 	 * estimator (p_estcpu) is increased here.  The formula for computing
449df8bae1dSRodney W. Grimes 	 * priorities (in kern_synch.c) will compute a different value each
450df8bae1dSRodney W. Grimes 	 * time p_estcpu increases by 4.  The cpu usage estimator ramps up
451df8bae1dSRodney W. Grimes 	 * quite quickly when the process is running (linearly), and decays
452df8bae1dSRodney W. Grimes 	 * away exponentially, at a rate which is proportionally slower when
453df8bae1dSRodney W. Grimes 	 * the system is busy.  The basic principal is that the system will
454df8bae1dSRodney W. Grimes 	 * 90% forget that the process used a lot of CPU time in 5 * loadav
455df8bae1dSRodney W. Grimes 	 * seconds.  This causes the system to favor processes which haven't
456df8bae1dSRodney W. Grimes 	 * run much recently, and to round-robin among other processes.
457df8bae1dSRodney W. Grimes 	 */
458df8bae1dSRodney W. Grimes 	if (p != NULL) {
459df8bae1dSRodney W. Grimes 		p->p_cpticks++;
460df8bae1dSRodney W. Grimes 		if (++p->p_estcpu == 0)
461df8bae1dSRodney W. Grimes 			p->p_estcpu--;
462df8bae1dSRodney W. Grimes 		if ((p->p_estcpu & 3) == 0) {
463df8bae1dSRodney W. Grimes 			resetpriority(p);
464df8bae1dSRodney W. Grimes 			if (p->p_priority >= PUSER)
465df8bae1dSRodney W. Grimes 				p->p_priority = p->p_usrpri;
466df8bae1dSRodney W. Grimes 		}
467f5e9e8ecSBruce Evans 
468f5e9e8ecSBruce Evans 		/* Update resource usage integrals and maximums. */
469f5e9e8ecSBruce Evans 		if ((pstats = p->p_stats) != NULL &&
470f5e9e8ecSBruce Evans 		    (ru = &pstats->p_ru) != NULL &&
471f5e9e8ecSBruce Evans 		    (vm = p->p_vmspace) != NULL) {
4721c6d46f9SLuoqi Chen 			ru->ru_ixrss += pgtok(vm->vm_tsize);
4731c6d46f9SLuoqi Chen 			ru->ru_idrss += pgtok(vm->vm_dsize);
4741c6d46f9SLuoqi Chen 			ru->ru_isrss += pgtok(vm->vm_ssize);
4751c6d46f9SLuoqi Chen 			rss = pgtok(vmspace_resident_count(vm));
476f5e9e8ecSBruce Evans 			if (ru->ru_maxrss < rss)
477f5e9e8ecSBruce Evans 				ru->ru_maxrss = rss;
478f5e9e8ecSBruce Evans         	}
479df8bae1dSRodney W. Grimes 	}
480df8bae1dSRodney W. Grimes }
481df8bae1dSRodney W. Grimes 
482df8bae1dSRodney W. Grimes /*
483df8bae1dSRodney W. Grimes  * Return information about system clocks.
484df8bae1dSRodney W. Grimes  */
485787d58f2SPoul-Henning Kamp static int
486787d58f2SPoul-Henning Kamp sysctl_kern_clockrate SYSCTL_HANDLER_ARGS
487df8bae1dSRodney W. Grimes {
488df8bae1dSRodney W. Grimes 	struct clockinfo clkinfo;
489df8bae1dSRodney W. Grimes 	/*
490df8bae1dSRodney W. Grimes 	 * Construct clockinfo structure.
491df8bae1dSRodney W. Grimes 	 */
492df8bae1dSRodney W. Grimes 	clkinfo.hz = hz;
493df8bae1dSRodney W. Grimes 	clkinfo.tick = tick;
4945faa3121SJohn Hay 	clkinfo.tickadj = tickadj;
495df8bae1dSRodney W. Grimes 	clkinfo.profhz = profhz;
496df8bae1dSRodney W. Grimes 	clkinfo.stathz = stathz ? stathz : hz;
497ae0eb976SPoul-Henning Kamp 	return (sysctl_handle_opaque(oidp, &clkinfo, sizeof clkinfo, req));
498df8bae1dSRodney W. Grimes }
4993f31c649SGarrett Wollman 
500946bb7a2SPoul-Henning Kamp SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD,
50165d0bc13SPoul-Henning Kamp 	0, 0, sysctl_kern_clockrate, "S,clockinfo","");
502787d58f2SPoul-Henning Kamp 
503e796e00dSPoul-Henning Kamp static __inline unsigned
504a58f0f8eSPoul-Henning Kamp tco_delta(struct timecounter *tc)
505e796e00dSPoul-Henning Kamp {
506e796e00dSPoul-Henning Kamp 
507a58f0f8eSPoul-Henning Kamp 	return ((tc->tc_get_timecount(tc) - tc->tc_offset_count) &
508a58f0f8eSPoul-Henning Kamp 	    tc->tc_counter_mask);
509e796e00dSPoul-Henning Kamp }
510a0502b19SPoul-Henning Kamp 
511a0502b19SPoul-Henning Kamp /*
51232c20357SPoul-Henning Kamp  * We have eight functions for looking at the clock, four for
51332c20357SPoul-Henning Kamp  * microseconds and four for nanoseconds.  For each there is fast
51432c20357SPoul-Henning Kamp  * but less precise version "get{nano|micro}[up]time" which will
51532c20357SPoul-Henning Kamp  * return a time which is up to 1/HZ previous to the call, whereas
51632c20357SPoul-Henning Kamp  * the raw version "{nano|micro}[up]time" will return a timestamp
51732c20357SPoul-Henning Kamp  * which is as precise as possible.  The "up" variants return the
51832c20357SPoul-Henning Kamp  * time relative to system boot, these are well suited for time
51932c20357SPoul-Henning Kamp  * interval measurements.
520a0502b19SPoul-Henning Kamp  */
521a0502b19SPoul-Henning Kamp 
522a0502b19SPoul-Henning Kamp void
523a0502b19SPoul-Henning Kamp getmicrotime(struct timeval *tvp)
524a0502b19SPoul-Henning Kamp {
525a0502b19SPoul-Henning Kamp 	struct timecounter *tc;
526a0502b19SPoul-Henning Kamp 
527510eb5b9SPoul-Henning Kamp 	if (!tco_method) {
528a0502b19SPoul-Henning Kamp 		tc = timecounter;
529a58f0f8eSPoul-Henning Kamp 		*tvp = tc->tc_microtime;
530510eb5b9SPoul-Henning Kamp 	} else {
531510eb5b9SPoul-Henning Kamp 		microtime(tvp);
532510eb5b9SPoul-Henning Kamp 	}
53300af9731SPoul-Henning Kamp }
53400af9731SPoul-Henning Kamp 
53500af9731SPoul-Henning Kamp void
53600af9731SPoul-Henning Kamp getnanotime(struct timespec *tsp)
53700af9731SPoul-Henning Kamp {
53800af9731SPoul-Henning Kamp 	struct timecounter *tc;
53900af9731SPoul-Henning Kamp 
540510eb5b9SPoul-Henning Kamp 	if (!tco_method) {
54100af9731SPoul-Henning Kamp 		tc = timecounter;
542a58f0f8eSPoul-Henning Kamp 		*tsp = tc->tc_nanotime;
543510eb5b9SPoul-Henning Kamp 	} else {
544510eb5b9SPoul-Henning Kamp 		nanotime(tsp);
545510eb5b9SPoul-Henning Kamp 	}
54600af9731SPoul-Henning Kamp }
54700af9731SPoul-Henning Kamp 
54800af9731SPoul-Henning Kamp void
54900af9731SPoul-Henning Kamp microtime(struct timeval *tv)
55000af9731SPoul-Henning Kamp {
55100af9731SPoul-Henning Kamp 	struct timecounter *tc;
55200af9731SPoul-Henning Kamp 
5537ac9503bSJohn Polstra 	tc = timecounter;
554a58f0f8eSPoul-Henning Kamp 	tv->tv_sec = tc->tc_offset_sec;
555a58f0f8eSPoul-Henning Kamp 	tv->tv_usec = tc->tc_offset_micro;
556a58f0f8eSPoul-Henning Kamp 	tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32;
55700af9731SPoul-Henning Kamp 	tv->tv_usec += boottime.tv_usec;
55800af9731SPoul-Henning Kamp 	tv->tv_sec += boottime.tv_sec;
55991ad39c6SPoul-Henning Kamp 	while (tv->tv_usec >= 1000000) {
56000af9731SPoul-Henning Kamp 		tv->tv_usec -= 1000000;
56100af9731SPoul-Henning Kamp 		tv->tv_sec++;
56200af9731SPoul-Henning Kamp 	}
56300af9731SPoul-Henning Kamp }
56400af9731SPoul-Henning Kamp 
56500af9731SPoul-Henning Kamp void
56648115288SPoul-Henning Kamp nanotime(struct timespec *ts)
56700af9731SPoul-Henning Kamp {
568579f4456SPoul-Henning Kamp 	unsigned count;
56900af9731SPoul-Henning Kamp 	u_int64_t delta;
57000af9731SPoul-Henning Kamp 	struct timecounter *tc;
57100af9731SPoul-Henning Kamp 
5727ac9503bSJohn Polstra 	tc = timecounter;
573a58f0f8eSPoul-Henning Kamp 	ts->tv_sec = tc->tc_offset_sec;
574a58f0f8eSPoul-Henning Kamp 	count = tco_delta(tc);
575a58f0f8eSPoul-Henning Kamp 	delta = tc->tc_offset_nano;
576a58f0f8eSPoul-Henning Kamp 	delta += ((u_int64_t)count * tc->tc_scale_nano_f);
57700af9731SPoul-Henning Kamp 	delta >>= 32;
578a58f0f8eSPoul-Henning Kamp 	delta += ((u_int64_t)count * tc->tc_scale_nano_i);
57900af9731SPoul-Henning Kamp 	delta += boottime.tv_usec * 1000;
58048115288SPoul-Henning Kamp 	ts->tv_sec += boottime.tv_sec;
58191ad39c6SPoul-Henning Kamp 	while (delta >= 1000000000) {
58200af9731SPoul-Henning Kamp 		delta -= 1000000000;
58348115288SPoul-Henning Kamp 		ts->tv_sec++;
58400af9731SPoul-Henning Kamp 	}
58548115288SPoul-Henning Kamp 	ts->tv_nsec = delta;
58648115288SPoul-Henning Kamp }
58748115288SPoul-Henning Kamp 
58848115288SPoul-Henning Kamp void
589c21410e1SPoul-Henning Kamp getmicrouptime(struct timeval *tvp)
59000af9731SPoul-Henning Kamp {
59100af9731SPoul-Henning Kamp 	struct timecounter *tc;
59200af9731SPoul-Henning Kamp 
593510eb5b9SPoul-Henning Kamp 	if (!tco_method) {
59400af9731SPoul-Henning Kamp 		tc = timecounter;
595a58f0f8eSPoul-Henning Kamp 		tvp->tv_sec = tc->tc_offset_sec;
596a58f0f8eSPoul-Henning Kamp 		tvp->tv_usec = tc->tc_offset_micro;
597510eb5b9SPoul-Henning Kamp 	} else {
598510eb5b9SPoul-Henning Kamp 		microuptime(tvp);
599510eb5b9SPoul-Henning Kamp 	}
600a0502b19SPoul-Henning Kamp }
601a0502b19SPoul-Henning Kamp 
602a0502b19SPoul-Henning Kamp void
603c21410e1SPoul-Henning Kamp getnanouptime(struct timespec *tsp)
604a0502b19SPoul-Henning Kamp {
605a0502b19SPoul-Henning Kamp 	struct timecounter *tc;
606a0502b19SPoul-Henning Kamp 
607510eb5b9SPoul-Henning Kamp 	if (!tco_method) {
608a0502b19SPoul-Henning Kamp 		tc = timecounter;
609a58f0f8eSPoul-Henning Kamp 		tsp->tv_sec = tc->tc_offset_sec;
610a58f0f8eSPoul-Henning Kamp 		tsp->tv_nsec = tc->tc_offset_nano >> 32;
611510eb5b9SPoul-Henning Kamp 	} else {
612510eb5b9SPoul-Henning Kamp 		nanouptime(tsp);
613510eb5b9SPoul-Henning Kamp 	}
614a0502b19SPoul-Henning Kamp }
615a0502b19SPoul-Henning Kamp 
616c7c9a816SPoul-Henning Kamp void
617c21410e1SPoul-Henning Kamp microuptime(struct timeval *tv)
618c7c9a816SPoul-Henning Kamp {
6197ec73f64SPoul-Henning Kamp 	struct timecounter *tc;
6207ec73f64SPoul-Henning Kamp 
6217ac9503bSJohn Polstra 	tc = timecounter;
622a58f0f8eSPoul-Henning Kamp 	tv->tv_sec = tc->tc_offset_sec;
623a58f0f8eSPoul-Henning Kamp 	tv->tv_usec = tc->tc_offset_micro;
624a58f0f8eSPoul-Henning Kamp 	tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32;
6257ec73f64SPoul-Henning Kamp 	if (tv->tv_usec >= 1000000) {
6267ec73f64SPoul-Henning Kamp 		tv->tv_usec -= 1000000;
6277ec73f64SPoul-Henning Kamp 		tv->tv_sec++;
628c7c9a816SPoul-Henning Kamp 	}
6297ec73f64SPoul-Henning Kamp }
6307ec73f64SPoul-Henning Kamp 
6317ec73f64SPoul-Henning Kamp void
632c2906d55SPoul-Henning Kamp nanouptime(struct timespec *ts)
6337ec73f64SPoul-Henning Kamp {
634e796e00dSPoul-Henning Kamp 	unsigned count;
6357ec73f64SPoul-Henning Kamp 	u_int64_t delta;
6367ec73f64SPoul-Henning Kamp 	struct timecounter *tc;
6377ec73f64SPoul-Henning Kamp 
6387ac9503bSJohn Polstra 	tc = timecounter;
639c2906d55SPoul-Henning Kamp 	ts->tv_sec = tc->tc_offset_sec;
640a58f0f8eSPoul-Henning Kamp 	count = tco_delta(tc);
641a58f0f8eSPoul-Henning Kamp 	delta = tc->tc_offset_nano;
642a58f0f8eSPoul-Henning Kamp 	delta += ((u_int64_t)count * tc->tc_scale_nano_f);
6437ec73f64SPoul-Henning Kamp 	delta >>= 32;
644a58f0f8eSPoul-Henning Kamp 	delta += ((u_int64_t)count * tc->tc_scale_nano_i);
6457ec73f64SPoul-Henning Kamp 	if (delta >= 1000000000) {
6467ec73f64SPoul-Henning Kamp 		delta -= 1000000000;
647c2906d55SPoul-Henning Kamp 		ts->tv_sec++;
6487ec73f64SPoul-Henning Kamp 	}
649c2906d55SPoul-Henning Kamp 	ts->tv_nsec = delta;
6507ec73f64SPoul-Henning Kamp }
6517ec73f64SPoul-Henning Kamp 
6527ec73f64SPoul-Henning Kamp static void
6537ec73f64SPoul-Henning Kamp tco_setscales(struct timecounter *tc)
6547ec73f64SPoul-Henning Kamp {
6557ec73f64SPoul-Henning Kamp 	u_int64_t scale;
6567ec73f64SPoul-Henning Kamp 
6577ec73f64SPoul-Henning Kamp 	scale = 1000000000LL << 32;
658c68996e2SPoul-Henning Kamp 	scale += tc->tc_adjustment;
6590bb2226aSPoul-Henning Kamp 	scale /= tc->tc_tweak->tc_frequency;
660a58f0f8eSPoul-Henning Kamp 	tc->tc_scale_micro = scale / 1000;
661a58f0f8eSPoul-Henning Kamp 	tc->tc_scale_nano_f = scale & 0xffffffff;
662a58f0f8eSPoul-Henning Kamp 	tc->tc_scale_nano_i = scale >> 32;
6637ec73f64SPoul-Henning Kamp }
6647ec73f64SPoul-Henning Kamp 
6657ec73f64SPoul-Henning Kamp void
6660bb2226aSPoul-Henning Kamp update_timecounter(struct timecounter *tc)
6670bb2226aSPoul-Henning Kamp {
6680bb2226aSPoul-Henning Kamp 	tco_setscales(tc);
6690bb2226aSPoul-Henning Kamp }
6700bb2226aSPoul-Henning Kamp 
6710bb2226aSPoul-Henning Kamp void
6727ec73f64SPoul-Henning Kamp init_timecounter(struct timecounter *tc)
6737ec73f64SPoul-Henning Kamp {
674f5ef029eSPoul-Henning Kamp 	struct timespec ts1;
6753bac064fSPoul-Henning Kamp 	struct timecounter *t1, *t2, *t3;
6767ec73f64SPoul-Henning Kamp 	int i;
6777ec73f64SPoul-Henning Kamp 
678a58f0f8eSPoul-Henning Kamp 	tc->tc_adjustment = 0;
6790bb2226aSPoul-Henning Kamp 	tc->tc_tweak = tc;
6807ec73f64SPoul-Henning Kamp 	tco_setscales(tc);
681a58f0f8eSPoul-Henning Kamp 	tc->tc_offset_count = tc->tc_get_timecount(tc);
6826b6ef746SBruce Evans 	if (timecounter == &dummy_timecounter)
6836b6ef746SBruce Evans 		tc->tc_avail = tc;
6846b6ef746SBruce Evans 	else {
6856b6ef746SBruce Evans 		tc->tc_avail = timecounter->tc_tweak->tc_avail;
6866b6ef746SBruce Evans 		timecounter->tc_tweak->tc_avail = tc;
6876b6ef746SBruce Evans 	}
6883bac064fSPoul-Henning Kamp 	MALLOC(t1, struct timecounter *, sizeof *t1, M_TIMECOUNTER, M_WAITOK);
6896b6ef746SBruce Evans 	tc->tc_other = t1;
6903bac064fSPoul-Henning Kamp 	*t1 = *tc;
6913bac064fSPoul-Henning Kamp 	t2 = t1;
6923bac064fSPoul-Henning Kamp 	for (i = 1; i < NTIMECOUNTER; i++) {
6933bac064fSPoul-Henning Kamp 		MALLOC(t3, struct timecounter *, sizeof *t3,
6943bac064fSPoul-Henning Kamp 		    M_TIMECOUNTER, M_WAITOK);
6953bac064fSPoul-Henning Kamp 		*t3 = *tc;
6963bac064fSPoul-Henning Kamp 		t3->tc_other = t2;
6973bac064fSPoul-Henning Kamp 		t2 = t3;
6983bac064fSPoul-Henning Kamp 	}
6993bac064fSPoul-Henning Kamp 	t1->tc_other = t3;
7003bac064fSPoul-Henning Kamp 	tc = t1;
7017ec73f64SPoul-Henning Kamp 
7023bac064fSPoul-Henning Kamp 	printf("Timecounter \"%s\"  frequency %lu Hz\n",
7033bac064fSPoul-Henning Kamp 	    tc->tc_name, (u_long)tc->tc_frequency);
7047ec73f64SPoul-Henning Kamp 
7057ec73f64SPoul-Henning Kamp 	/* XXX: For now always start using the counter. */
706a58f0f8eSPoul-Henning Kamp 	tc->tc_offset_count = tc->tc_get_timecount(tc);
7076ca4ca24SPoul-Henning Kamp 	nanouptime(&ts1);
708a58f0f8eSPoul-Henning Kamp 	tc->tc_offset_nano = (u_int64_t)ts1.tv_nsec << 32;
709a58f0f8eSPoul-Henning Kamp 	tc->tc_offset_micro = ts1.tv_nsec / 1000;
710a58f0f8eSPoul-Henning Kamp 	tc->tc_offset_sec = ts1.tv_sec;
7117ec73f64SPoul-Henning Kamp 	timecounter = tc;
7127ec73f64SPoul-Henning Kamp }
7137ec73f64SPoul-Henning Kamp 
7147ec73f64SPoul-Henning Kamp void
7157ec73f64SPoul-Henning Kamp set_timecounter(struct timespec *ts)
7167ec73f64SPoul-Henning Kamp {
71700af9731SPoul-Henning Kamp 	struct timespec ts2;
7187ec73f64SPoul-Henning Kamp 
719c21410e1SPoul-Henning Kamp 	nanouptime(&ts2);
72000af9731SPoul-Henning Kamp 	boottime.tv_sec = ts->tv_sec - ts2.tv_sec;
72100af9731SPoul-Henning Kamp 	boottime.tv_usec = (ts->tv_nsec - ts2.tv_nsec) / 1000;
72200af9731SPoul-Henning Kamp 	if (boottime.tv_usec < 0) {
72300af9731SPoul-Henning Kamp 		boottime.tv_usec += 1000000;
72400af9731SPoul-Henning Kamp 		boottime.tv_sec--;
72500af9731SPoul-Henning Kamp 	}
72600af9731SPoul-Henning Kamp 	/* fiddle all the little crinkly bits around the fiords... */
727c2906d55SPoul-Henning Kamp 	tco_forward(1);
7287ec73f64SPoul-Henning Kamp }
7297ec73f64SPoul-Henning Kamp 
7306b6ef746SBruce Evans static void
731b05dcf3cSPoul-Henning Kamp switch_timecounter(struct timecounter *newtc)
732b05dcf3cSPoul-Henning Kamp {
733b05dcf3cSPoul-Henning Kamp 	int s;
734b05dcf3cSPoul-Henning Kamp 	struct timecounter *tc;
735b05dcf3cSPoul-Henning Kamp 	struct timespec ts;
736b05dcf3cSPoul-Henning Kamp 
737b05dcf3cSPoul-Henning Kamp 	s = splclock();
738b05dcf3cSPoul-Henning Kamp 	tc = timecounter;
7396b6ef746SBruce Evans 	if (newtc->tc_tweak == tc->tc_tweak) {
740b05dcf3cSPoul-Henning Kamp 		splx(s);
741b05dcf3cSPoul-Henning Kamp 		return;
742b05dcf3cSPoul-Henning Kamp 	}
7436b6ef746SBruce Evans 	newtc = newtc->tc_tweak->tc_other;
7446ca4ca24SPoul-Henning Kamp 	nanouptime(&ts);
745a58f0f8eSPoul-Henning Kamp 	newtc->tc_offset_sec = ts.tv_sec;
746a58f0f8eSPoul-Henning Kamp 	newtc->tc_offset_nano = (u_int64_t)ts.tv_nsec << 32;
747a58f0f8eSPoul-Henning Kamp 	newtc->tc_offset_micro = ts.tv_nsec / 1000;
748a58f0f8eSPoul-Henning Kamp 	newtc->tc_offset_count = newtc->tc_get_timecount(newtc);
7496b6ef746SBruce Evans 	tco_setscales(newtc);
750b05dcf3cSPoul-Henning Kamp 	timecounter = newtc;
751b05dcf3cSPoul-Henning Kamp 	splx(s);
752b05dcf3cSPoul-Henning Kamp }
753b05dcf3cSPoul-Henning Kamp 
7547ec73f64SPoul-Henning Kamp static struct timecounter *
755b05dcf3cSPoul-Henning Kamp sync_other_counter(void)
7567ec73f64SPoul-Henning Kamp {
7570edd53d2SPoul-Henning Kamp 	struct timecounter *tc, *tcn, *tco;
758579f4456SPoul-Henning Kamp 	unsigned delta;
7597ec73f64SPoul-Henning Kamp 
7600edd53d2SPoul-Henning Kamp 	tco = timecounter;
7610edd53d2SPoul-Henning Kamp 	tc = tco->tc_other;
7620edd53d2SPoul-Henning Kamp 	tcn = tc->tc_other;
7630edd53d2SPoul-Henning Kamp 	*tc = *tco;
7640edd53d2SPoul-Henning Kamp 	tc->tc_other = tcn;
765a58f0f8eSPoul-Henning Kamp 	delta = tco_delta(tc);
766a58f0f8eSPoul-Henning Kamp 	tc->tc_offset_count += delta;
767a58f0f8eSPoul-Henning Kamp 	tc->tc_offset_count &= tc->tc_counter_mask;
768a58f0f8eSPoul-Henning Kamp 	tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_f;
769a58f0f8eSPoul-Henning Kamp 	tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_i << 32;
7707ec73f64SPoul-Henning Kamp 	return (tc);
7717ec73f64SPoul-Henning Kamp }
7727ec73f64SPoul-Henning Kamp 
7737ec73f64SPoul-Henning Kamp static void
774c2906d55SPoul-Henning Kamp tco_forward(int force)
7757ec73f64SPoul-Henning Kamp {
77652f8e5d6SPoul-Henning Kamp 	struct timecounter *tc, *tco;
7777ec73f64SPoul-Henning Kamp 
77852f8e5d6SPoul-Henning Kamp 	tco = timecounter;
779b05dcf3cSPoul-Henning Kamp 	tc = sync_other_counter();
7800edd53d2SPoul-Henning Kamp 	/*
7810edd53d2SPoul-Henning Kamp 	 * We may be inducing a tiny error here, the tc_poll_pps() may
7820edd53d2SPoul-Henning Kamp 	 * process a latched count which happens after the tco_delta()
7830edd53d2SPoul-Henning Kamp 	 * in sync_other_counter(), which would extend the previous
7840edd53d2SPoul-Henning Kamp 	 * counters parameters into the domain of this new one.
7850edd53d2SPoul-Henning Kamp 	 * Since the timewindow is very small for this, the error is
7860edd53d2SPoul-Henning Kamp 	 * going to be only a few weenieseconds (as Dave Mills would
7870edd53d2SPoul-Henning Kamp 	 * say), so lets just not talk more about it, OK ?
7880edd53d2SPoul-Henning Kamp 	 */
78952f8e5d6SPoul-Henning Kamp 	if (tco->tc_poll_pps)
79052f8e5d6SPoul-Henning Kamp 		tco->tc_poll_pps(tco);
791b05dcf3cSPoul-Henning Kamp 	if (timedelta != 0) {
792a58f0f8eSPoul-Henning Kamp 		tc->tc_offset_nano += (u_int64_t)(tickdelta * 1000) << 32;
7937ec73f64SPoul-Henning Kamp 		timedelta -= tickdelta;
794c2906d55SPoul-Henning Kamp 		force++;
7957ec73f64SPoul-Henning Kamp 	}
796b05dcf3cSPoul-Henning Kamp 
797a58f0f8eSPoul-Henning Kamp 	while (tc->tc_offset_nano >= 1000000000ULL << 32) {
798a58f0f8eSPoul-Henning Kamp 		tc->tc_offset_nano -= 1000000000ULL << 32;
799a58f0f8eSPoul-Henning Kamp 		tc->tc_offset_sec++;
8007ec73f64SPoul-Henning Kamp 		ntp_update_second(tc);	/* XXX only needed if xntpd runs */
8017ec73f64SPoul-Henning Kamp 		tco_setscales(tc);
802c2906d55SPoul-Henning Kamp 		force++;
8037ec73f64SPoul-Henning Kamp 	}
804b05dcf3cSPoul-Henning Kamp 
805510eb5b9SPoul-Henning Kamp 	if (tco_method && !force)
806c2906d55SPoul-Henning Kamp 		return;
807c2906d55SPoul-Henning Kamp 
808a58f0f8eSPoul-Henning Kamp 	tc->tc_offset_micro = (tc->tc_offset_nano / 1000) >> 32;
809b05dcf3cSPoul-Henning Kamp 
81000af9731SPoul-Henning Kamp 	/* Figure out the wall-clock time */
811a58f0f8eSPoul-Henning Kamp 	tc->tc_nanotime.tv_sec = tc->tc_offset_sec + boottime.tv_sec;
812a58f0f8eSPoul-Henning Kamp 	tc->tc_nanotime.tv_nsec =
813a58f0f8eSPoul-Henning Kamp 	    (tc->tc_offset_nano >> 32) + boottime.tv_usec * 1000;
814a58f0f8eSPoul-Henning Kamp 	tc->tc_microtime.tv_usec = tc->tc_offset_micro + boottime.tv_usec;
815a58f0f8eSPoul-Henning Kamp 	if (tc->tc_nanotime.tv_nsec >= 1000000000) {
816a58f0f8eSPoul-Henning Kamp 		tc->tc_nanotime.tv_nsec -= 1000000000;
817a58f0f8eSPoul-Henning Kamp 		tc->tc_microtime.tv_usec -= 1000000;
818a58f0f8eSPoul-Henning Kamp 		tc->tc_nanotime.tv_sec++;
81900af9731SPoul-Henning Kamp 	}
820a58f0f8eSPoul-Henning Kamp 	time_second = tc->tc_microtime.tv_sec = tc->tc_nanotime.tv_sec;
82100af9731SPoul-Henning Kamp 
8227ec73f64SPoul-Henning Kamp 	timecounter = tc;
8237ec73f64SPoul-Henning Kamp }
8247ec73f64SPoul-Henning Kamp 
8257ec73f64SPoul-Henning Kamp SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
8267ec73f64SPoul-Henning Kamp 
82730f27235SPoul-Henning Kamp SYSCTL_INT(_kern_timecounter, OID_AUTO, method, CTLFLAG_RW, &tco_method, 0,
828510eb5b9SPoul-Henning Kamp     "This variable determines the method used for updating timecounters. "
829510eb5b9SPoul-Henning Kamp     "If the default algorithm (0) fails with \"calcru negative...\" messages "
830510eb5b9SPoul-Henning Kamp     "try the alternate algorithm (1) which handles bad hardware better."
831510eb5b9SPoul-Henning Kamp 
832510eb5b9SPoul-Henning Kamp );
833510eb5b9SPoul-Henning Kamp 
8346b6ef746SBruce Evans static int
8356b6ef746SBruce Evans sysctl_kern_timecounter_hardware SYSCTL_HANDLER_ARGS
8366b6ef746SBruce Evans {
8376b6ef746SBruce Evans 	char newname[32];
8386b6ef746SBruce Evans 	struct timecounter *newtc, *tc;
8396b6ef746SBruce Evans 	int error;
8406b6ef746SBruce Evans 
8416b6ef746SBruce Evans 	tc = timecounter->tc_tweak;
8426b6ef746SBruce Evans 	strncpy(newname, tc->tc_name, sizeof(newname));
8436b6ef746SBruce Evans 	error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req);
8446b6ef746SBruce Evans 	if (error == 0 && req->newptr != NULL &&
8456b6ef746SBruce Evans 	    strcmp(newname, tc->tc_name) != 0) {
846a1a10fdfSBruce Evans 		for (newtc = tc->tc_avail; newtc != tc;
847a1a10fdfSBruce Evans 		    newtc = newtc->tc_avail) {
8486b6ef746SBruce Evans 			if (strcmp(newname, newtc->tc_name) == 0) {
8496b6ef746SBruce Evans 				/* Warm up new timecounter. */
8506b6ef746SBruce Evans 				(void)newtc->tc_get_timecount(newtc);
8516b6ef746SBruce Evans 
8526b6ef746SBruce Evans 				switch_timecounter(newtc);
8536b6ef746SBruce Evans 				return (0);
8546b6ef746SBruce Evans 			}
8556b6ef746SBruce Evans 		}
8566b6ef746SBruce Evans 		return (EINVAL);
8576b6ef746SBruce Evans 	}
8586b6ef746SBruce Evans 	return (error);
8596b6ef746SBruce Evans }
8606b6ef746SBruce Evans 
8616b6ef746SBruce Evans SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW,
8626b6ef746SBruce Evans     0, 0, sysctl_kern_timecounter_hardware, "A", "");
8636b6ef746SBruce Evans 
8647ec73f64SPoul-Henning Kamp 
86532c20357SPoul-Henning Kamp int
86632c20357SPoul-Henning Kamp pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps)
86732c20357SPoul-Henning Kamp {
86832c20357SPoul-Henning Kamp         pps_params_t *app;
86932c20357SPoul-Henning Kamp         pps_info_t *api;
87032c20357SPoul-Henning Kamp 
87132c20357SPoul-Henning Kamp         switch (cmd) {
87232c20357SPoul-Henning Kamp         case PPS_IOC_CREATE:
87332c20357SPoul-Henning Kamp                 return (0);
87432c20357SPoul-Henning Kamp         case PPS_IOC_DESTROY:
87532c20357SPoul-Henning Kamp                 return (0);
87632c20357SPoul-Henning Kamp         case PPS_IOC_SETPARAMS:
87732c20357SPoul-Henning Kamp                 app = (pps_params_t *)data;
87832c20357SPoul-Henning Kamp                 if (app->mode & ~pps->ppscap)
87932c20357SPoul-Henning Kamp                         return (EINVAL);
88032c20357SPoul-Henning Kamp                 pps->ppsparam = *app;
88132c20357SPoul-Henning Kamp                 return (0);
88232c20357SPoul-Henning Kamp         case PPS_IOC_GETPARAMS:
88332c20357SPoul-Henning Kamp                 app = (pps_params_t *)data;
88432c20357SPoul-Henning Kamp                 *app = pps->ppsparam;
88532c20357SPoul-Henning Kamp                 return (0);
88632c20357SPoul-Henning Kamp         case PPS_IOC_GETCAP:
88732c20357SPoul-Henning Kamp                 *(int*)data = pps->ppscap;
88832c20357SPoul-Henning Kamp                 return (0);
88932c20357SPoul-Henning Kamp         case PPS_IOC_FETCH:
89032c20357SPoul-Henning Kamp                 api = (pps_info_t *)data;
89132c20357SPoul-Henning Kamp                 pps->ppsinfo.current_mode = pps->ppsparam.mode;
89232c20357SPoul-Henning Kamp                 *api = pps->ppsinfo;
89332c20357SPoul-Henning Kamp                 return (0);
89432c20357SPoul-Henning Kamp         case PPS_IOC_WAIT:
89532c20357SPoul-Henning Kamp                 return (EOPNOTSUPP);
89632c20357SPoul-Henning Kamp         default:
89732c20357SPoul-Henning Kamp                 return (ENOTTY);
89832c20357SPoul-Henning Kamp         }
89932c20357SPoul-Henning Kamp }
90032c20357SPoul-Henning Kamp 
90132c20357SPoul-Henning Kamp void
90232c20357SPoul-Henning Kamp pps_init(struct pps_state *pps)
90332c20357SPoul-Henning Kamp {
90432c20357SPoul-Henning Kamp 	pps->ppscap |= PPS_TSFMT_TSPEC;
90532c20357SPoul-Henning Kamp 	if (pps->ppscap & PPS_CAPTUREASSERT)
90632c20357SPoul-Henning Kamp 		pps->ppscap |= PPS_OFFSETASSERT;
90732c20357SPoul-Henning Kamp 	if (pps->ppscap & PPS_CAPTURECLEAR)
90832c20357SPoul-Henning Kamp 		pps->ppscap |= PPS_OFFSETCLEAR;
90932c20357SPoul-Henning Kamp #ifdef PPS_SYNC
91032c20357SPoul-Henning Kamp 	if (pps->ppscap & PPS_CAPTUREASSERT)
91132c20357SPoul-Henning Kamp 		pps->ppscap |= PPS_HARDPPSONASSERT;
91232c20357SPoul-Henning Kamp 	if (pps->ppscap & PPS_CAPTURECLEAR)
91332c20357SPoul-Henning Kamp 		pps->ppscap |= PPS_HARDPPSONCLEAR;
91432c20357SPoul-Henning Kamp #endif
91532c20357SPoul-Henning Kamp }
91632c20357SPoul-Henning Kamp 
91732c20357SPoul-Henning Kamp void
91832c20357SPoul-Henning Kamp pps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int event)
91932c20357SPoul-Henning Kamp {
92032c20357SPoul-Henning Kamp 	struct timespec ts, *tsp, *osp;
92132c20357SPoul-Henning Kamp 	u_int64_t delta;
92232c20357SPoul-Henning Kamp 	unsigned tcount, *pcount;
92332c20357SPoul-Henning Kamp 	int foff, fhard;
92432c20357SPoul-Henning Kamp 	pps_seq_t	*pseq;
92532c20357SPoul-Henning Kamp 
92632c20357SPoul-Henning Kamp 	/* Things would be easier with arrays... */
92732c20357SPoul-Henning Kamp 	if (event == PPS_CAPTUREASSERT) {
92832c20357SPoul-Henning Kamp 		tsp = &pps->ppsinfo.assert_timestamp;
92932c20357SPoul-Henning Kamp 		osp = &pps->ppsparam.assert_offset;
93032c20357SPoul-Henning Kamp 		foff = pps->ppsparam.mode & PPS_OFFSETASSERT;
93132c20357SPoul-Henning Kamp 		fhard = pps->ppsparam.mode & PPS_HARDPPSONASSERT;
93232c20357SPoul-Henning Kamp 		pcount = &pps->ppscount[0];
93332c20357SPoul-Henning Kamp 		pseq = &pps->ppsinfo.assert_sequence;
93432c20357SPoul-Henning Kamp 	} else {
93532c20357SPoul-Henning Kamp 		tsp = &pps->ppsinfo.clear_timestamp;
93632c20357SPoul-Henning Kamp 		osp = &pps->ppsparam.clear_offset;
93732c20357SPoul-Henning Kamp 		foff = pps->ppsparam.mode & PPS_OFFSETCLEAR;
93832c20357SPoul-Henning Kamp 		fhard = pps->ppsparam.mode & PPS_HARDPPSONCLEAR;
93932c20357SPoul-Henning Kamp 		pcount = &pps->ppscount[1];
94032c20357SPoul-Henning Kamp 		pseq = &pps->ppsinfo.clear_sequence;
94132c20357SPoul-Henning Kamp 	}
94232c20357SPoul-Henning Kamp 
94332c20357SPoul-Henning Kamp 	/* The timecounter changed: bail */
94432c20357SPoul-Henning Kamp 	if (!pps->ppstc ||
94532c20357SPoul-Henning Kamp 	    pps->ppstc->tc_name != tc->tc_name ||
94632c20357SPoul-Henning Kamp 	    tc->tc_name != timecounter->tc_name) {
94732c20357SPoul-Henning Kamp 		pps->ppstc = tc;
94832c20357SPoul-Henning Kamp 		*pcount = count;
94932c20357SPoul-Henning Kamp 		return;
95032c20357SPoul-Henning Kamp 	}
95132c20357SPoul-Henning Kamp 
95232c20357SPoul-Henning Kamp 	/* Nothing really happened */
95332c20357SPoul-Henning Kamp 	if (*pcount == count)
95432c20357SPoul-Henning Kamp 		return;
95532c20357SPoul-Henning Kamp 
95632c20357SPoul-Henning Kamp 	*pcount = count;
95732c20357SPoul-Henning Kamp 
95832c20357SPoul-Henning Kamp 	/* Convert the count to timespec */
95932c20357SPoul-Henning Kamp 	ts.tv_sec = tc->tc_offset_sec;
96032c20357SPoul-Henning Kamp 	tcount = count - tc->tc_offset_count;
96132c20357SPoul-Henning Kamp 	tcount &= tc->tc_counter_mask;
96232c20357SPoul-Henning Kamp 	delta = tc->tc_offset_nano;
96332c20357SPoul-Henning Kamp 	delta += ((u_int64_t)tcount * tc->tc_scale_nano_f);
96432c20357SPoul-Henning Kamp 	delta >>= 32;
96532c20357SPoul-Henning Kamp 	delta += ((u_int64_t)tcount * tc->tc_scale_nano_i);
96632c20357SPoul-Henning Kamp 	delta += boottime.tv_usec * 1000;
96732c20357SPoul-Henning Kamp 	ts.tv_sec += boottime.tv_sec;
96832c20357SPoul-Henning Kamp 	while (delta >= 1000000000) {
96932c20357SPoul-Henning Kamp 		delta -= 1000000000;
97032c20357SPoul-Henning Kamp 		ts.tv_sec++;
97132c20357SPoul-Henning Kamp 	}
97232c20357SPoul-Henning Kamp 	ts.tv_nsec = delta;
97332c20357SPoul-Henning Kamp 
97432c20357SPoul-Henning Kamp 	(*pseq)++;
97532c20357SPoul-Henning Kamp 	*tsp = ts;
97632c20357SPoul-Henning Kamp 
97732c20357SPoul-Henning Kamp 	if (foff) {
97832c20357SPoul-Henning Kamp 		timespecadd(tsp, osp);
97932c20357SPoul-Henning Kamp 		if (tsp->tv_nsec < 0) {
98032c20357SPoul-Henning Kamp 			tsp->tv_nsec += 1000000000;
98132c20357SPoul-Henning Kamp 			tsp->tv_sec -= 1;
98232c20357SPoul-Henning Kamp 		}
98332c20357SPoul-Henning Kamp 	}
98432c20357SPoul-Henning Kamp #ifdef PPS_SYNC
98532c20357SPoul-Henning Kamp 	if (fhard) {
98632c20357SPoul-Henning Kamp 		/* magic, at its best... */
98732c20357SPoul-Henning Kamp 		tcount = count - pps->ppscount[2];
98832c20357SPoul-Henning Kamp 		pps->ppscount[2] = count;
98932c20357SPoul-Henning Kamp 		tcount &= tc->tc_counter_mask;
99032c20357SPoul-Henning Kamp 		delta = ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_f);
99132c20357SPoul-Henning Kamp 		delta >>= 32;
99232c20357SPoul-Henning Kamp 		delta += ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_i);
99332c20357SPoul-Henning Kamp 		hardpps(tsp, delta);
99432c20357SPoul-Henning Kamp 	}
99532c20357SPoul-Henning Kamp #endif
99632c20357SPoul-Henning Kamp }
99732c20357SPoul-Henning Kamp 
998