xref: /freebsd/sys/kern/kern_clocksource.c (revision 43fe7d458a2b5adc2ffdd426624e58b16a8769cf)
1*43fe7d45SAlexander Motin /*-
2*43fe7d45SAlexander Motin  * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
3*43fe7d45SAlexander Motin  * All rights reserved.
4*43fe7d45SAlexander Motin  *
5*43fe7d45SAlexander Motin  * Redistribution and use in source and binary forms, with or without
6*43fe7d45SAlexander Motin  * modification, are permitted provided that the following conditions
7*43fe7d45SAlexander Motin  * are met:
8*43fe7d45SAlexander Motin  * 1. Redistributions of source code must retain the above copyright
9*43fe7d45SAlexander Motin  *    notice, this list of conditions and the following disclaimer,
10*43fe7d45SAlexander Motin  *    without modification, immediately at the beginning of the file.
11*43fe7d45SAlexander Motin  * 2. Redistributions in binary form must reproduce the above copyright
12*43fe7d45SAlexander Motin  *    notice, this list of conditions and the following disclaimer in the
13*43fe7d45SAlexander Motin  *    documentation and/or other materials provided with the distribution.
14*43fe7d45SAlexander Motin  *
15*43fe7d45SAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16*43fe7d45SAlexander Motin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17*43fe7d45SAlexander Motin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18*43fe7d45SAlexander Motin  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19*43fe7d45SAlexander Motin  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20*43fe7d45SAlexander Motin  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21*43fe7d45SAlexander Motin  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22*43fe7d45SAlexander Motin  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23*43fe7d45SAlexander Motin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24*43fe7d45SAlexander Motin  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*43fe7d45SAlexander Motin  */
26*43fe7d45SAlexander Motin 
27*43fe7d45SAlexander Motin #include <sys/cdefs.h>
28*43fe7d45SAlexander Motin __FBSDID("$FreeBSD$");
29*43fe7d45SAlexander Motin 
30*43fe7d45SAlexander Motin /*
31*43fe7d45SAlexander Motin  * Common routines to manage event timers hardware.
32*43fe7d45SAlexander Motin  */
33*43fe7d45SAlexander Motin 
34*43fe7d45SAlexander Motin /* XEN has own timer routines now. */
35*43fe7d45SAlexander Motin #ifndef XEN
36*43fe7d45SAlexander Motin 
37*43fe7d45SAlexander Motin #include "opt_kdtrace.h"
38*43fe7d45SAlexander Motin 
39*43fe7d45SAlexander Motin #include <sys/param.h>
40*43fe7d45SAlexander Motin #include <sys/systm.h>
41*43fe7d45SAlexander Motin #include <sys/bus.h>
42*43fe7d45SAlexander Motin #include <sys/lock.h>
43*43fe7d45SAlexander Motin #include <sys/kdb.h>
44*43fe7d45SAlexander Motin #include <sys/mutex.h>
45*43fe7d45SAlexander Motin #include <sys/proc.h>
46*43fe7d45SAlexander Motin #include <sys/kernel.h>
47*43fe7d45SAlexander Motin #include <sys/sched.h>
48*43fe7d45SAlexander Motin #include <sys/smp.h>
49*43fe7d45SAlexander Motin #include <sys/sysctl.h>
50*43fe7d45SAlexander Motin #include <sys/timeet.h>
51*43fe7d45SAlexander Motin 
52*43fe7d45SAlexander Motin #include <machine/atomic.h>
53*43fe7d45SAlexander Motin #include <machine/clock.h>
54*43fe7d45SAlexander Motin #include <machine/cpu.h>
55*43fe7d45SAlexander Motin #include <machine/smp.h>
56*43fe7d45SAlexander Motin 
57*43fe7d45SAlexander Motin #ifdef KDTRACE_HOOKS
58*43fe7d45SAlexander Motin #include <sys/dtrace_bsd.h>
59*43fe7d45SAlexander Motin cyclic_clock_func_t	cyclic_clock_func[MAXCPU];
60*43fe7d45SAlexander Motin #endif
61*43fe7d45SAlexander Motin 
62*43fe7d45SAlexander Motin static void		cpu_restartclocks(void);
63*43fe7d45SAlexander Motin static void		timercheck(void);
64*43fe7d45SAlexander Motin inline static int	doconfigtimer(int i);
65*43fe7d45SAlexander Motin static void		configtimer(int i);
66*43fe7d45SAlexander Motin 
67*43fe7d45SAlexander Motin static struct eventtimer *timer[2] = { NULL, NULL };
68*43fe7d45SAlexander Motin static int		timertest = 0;
69*43fe7d45SAlexander Motin static int		timerticks[2] = { 0, 0 };
70*43fe7d45SAlexander Motin static int		profiling_on = 0;
71*43fe7d45SAlexander Motin static struct bintime	timerperiod[2];
72*43fe7d45SAlexander Motin 
73*43fe7d45SAlexander Motin static char		timername[2][32];
74*43fe7d45SAlexander Motin TUNABLE_STR("kern.eventtimer.timer1", timername[0], sizeof(*timername));
75*43fe7d45SAlexander Motin TUNABLE_STR("kern.eventtimer.timer2", timername[1], sizeof(*timername));
76*43fe7d45SAlexander Motin 
77*43fe7d45SAlexander Motin static u_int		singlemul = 0;
78*43fe7d45SAlexander Motin TUNABLE_INT("kern.eventtimer.singlemul", &singlemul);
79*43fe7d45SAlexander Motin SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul,
80*43fe7d45SAlexander Motin     0, "Multiplier, used in single timer mode");
81*43fe7d45SAlexander Motin 
82*43fe7d45SAlexander Motin typedef u_int tc[2];
83*43fe7d45SAlexander Motin static DPCPU_DEFINE(tc, configtimer);
84*43fe7d45SAlexander Motin 
85*43fe7d45SAlexander Motin #define FREQ2BT(freq, bt)						\
86*43fe7d45SAlexander Motin {									\
87*43fe7d45SAlexander Motin 	(bt)->sec = 0;							\
88*43fe7d45SAlexander Motin 	(bt)->frac = ((uint64_t)0x8000000000000000  / (freq)) << 1;	\
89*43fe7d45SAlexander Motin }
90*43fe7d45SAlexander Motin #define BT2FREQ(bt, freq)						\
91*43fe7d45SAlexander Motin {									\
92*43fe7d45SAlexander Motin 	*(freq) = ((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) /	\
93*43fe7d45SAlexander Motin 		    ((bt)->frac >> 1);					\
94*43fe7d45SAlexander Motin }
95*43fe7d45SAlexander Motin 
96*43fe7d45SAlexander Motin /* Per-CPU timer1 handler. */
97*43fe7d45SAlexander Motin static int
98*43fe7d45SAlexander Motin hardclockhandler(struct trapframe *frame)
99*43fe7d45SAlexander Motin {
100*43fe7d45SAlexander Motin 
101*43fe7d45SAlexander Motin #ifdef KDTRACE_HOOKS
102*43fe7d45SAlexander Motin 	/*
103*43fe7d45SAlexander Motin 	 * If the DTrace hooks are configured and a callback function
104*43fe7d45SAlexander Motin 	 * has been registered, then call it to process the high speed
105*43fe7d45SAlexander Motin 	 * timers.
106*43fe7d45SAlexander Motin 	 */
107*43fe7d45SAlexander Motin 	int cpu = curcpu;
108*43fe7d45SAlexander Motin 	if (cyclic_clock_func[cpu] != NULL)
109*43fe7d45SAlexander Motin 		(*cyclic_clock_func[cpu])(frame);
110*43fe7d45SAlexander Motin #endif
111*43fe7d45SAlexander Motin 
112*43fe7d45SAlexander Motin 	timer1clock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
113*43fe7d45SAlexander Motin 	return (FILTER_HANDLED);
114*43fe7d45SAlexander Motin }
115*43fe7d45SAlexander Motin 
116*43fe7d45SAlexander Motin /* Per-CPU timer2 handler. */
117*43fe7d45SAlexander Motin static int
118*43fe7d45SAlexander Motin statclockhandler(struct trapframe *frame)
119*43fe7d45SAlexander Motin {
120*43fe7d45SAlexander Motin 
121*43fe7d45SAlexander Motin 	timer2clock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
122*43fe7d45SAlexander Motin 	return (FILTER_HANDLED);
123*43fe7d45SAlexander Motin }
124*43fe7d45SAlexander Motin 
125*43fe7d45SAlexander Motin /* timer1 broadcast IPI handler. */
126*43fe7d45SAlexander Motin int
127*43fe7d45SAlexander Motin hardclockintr(struct trapframe *frame)
128*43fe7d45SAlexander Motin {
129*43fe7d45SAlexander Motin 
130*43fe7d45SAlexander Motin 	if (doconfigtimer(0))
131*43fe7d45SAlexander Motin 		return (FILTER_HANDLED);
132*43fe7d45SAlexander Motin 	return (hardclockhandler(frame));
133*43fe7d45SAlexander Motin }
134*43fe7d45SAlexander Motin 
135*43fe7d45SAlexander Motin /* timer2 broadcast IPI handler. */
136*43fe7d45SAlexander Motin int
137*43fe7d45SAlexander Motin statclockintr(struct trapframe *frame)
138*43fe7d45SAlexander Motin {
139*43fe7d45SAlexander Motin 
140*43fe7d45SAlexander Motin 	if (doconfigtimer(1))
141*43fe7d45SAlexander Motin 		return (FILTER_HANDLED);
142*43fe7d45SAlexander Motin 	return (statclockhandler(frame));
143*43fe7d45SAlexander Motin }
144*43fe7d45SAlexander Motin 
145*43fe7d45SAlexander Motin /* timer1 callback. */
146*43fe7d45SAlexander Motin static void
147*43fe7d45SAlexander Motin timer1cb(struct eventtimer *et, void *arg)
148*43fe7d45SAlexander Motin {
149*43fe7d45SAlexander Motin 
150*43fe7d45SAlexander Motin #ifdef SMP
151*43fe7d45SAlexander Motin 	/* Broadcast interrupt to other CPUs for non-per-CPU timers */
152*43fe7d45SAlexander Motin 	if (smp_started && (et->et_flags & ET_FLAGS_PERCPU) == 0)
153*43fe7d45SAlexander Motin 		ipi_all_but_self(IPI_HARDCLOCK);
154*43fe7d45SAlexander Motin #endif
155*43fe7d45SAlexander Motin 	if (timertest) {
156*43fe7d45SAlexander Motin 		if ((et->et_flags & ET_FLAGS_PERCPU) == 0 || curcpu == 0) {
157*43fe7d45SAlexander Motin 			timerticks[0]++;
158*43fe7d45SAlexander Motin 			if (timerticks[0] >= timer1hz) {
159*43fe7d45SAlexander Motin 				ET_LOCK();
160*43fe7d45SAlexander Motin 				timercheck();
161*43fe7d45SAlexander Motin 				ET_UNLOCK();
162*43fe7d45SAlexander Motin 			}
163*43fe7d45SAlexander Motin 		}
164*43fe7d45SAlexander Motin 	}
165*43fe7d45SAlexander Motin 	hardclockhandler(curthread->td_intr_frame);
166*43fe7d45SAlexander Motin }
167*43fe7d45SAlexander Motin 
168*43fe7d45SAlexander Motin /* timer2 callback. */
169*43fe7d45SAlexander Motin static void
170*43fe7d45SAlexander Motin timer2cb(struct eventtimer *et, void *arg)
171*43fe7d45SAlexander Motin {
172*43fe7d45SAlexander Motin 
173*43fe7d45SAlexander Motin #ifdef SMP
174*43fe7d45SAlexander Motin 	/* Broadcast interrupt to other CPUs for non-per-CPU timers */
175*43fe7d45SAlexander Motin 	if (smp_started && (et->et_flags & ET_FLAGS_PERCPU) == 0)
176*43fe7d45SAlexander Motin 		ipi_all_but_self(IPI_STATCLOCK);
177*43fe7d45SAlexander Motin #endif
178*43fe7d45SAlexander Motin 	if (timertest) {
179*43fe7d45SAlexander Motin 		if ((et->et_flags & ET_FLAGS_PERCPU) == 0 || curcpu == 0) {
180*43fe7d45SAlexander Motin 			timerticks[1]++;
181*43fe7d45SAlexander Motin 			if (timerticks[1] >= timer2hz * 2) {
182*43fe7d45SAlexander Motin 				ET_LOCK();
183*43fe7d45SAlexander Motin 				timercheck();
184*43fe7d45SAlexander Motin 				ET_UNLOCK();
185*43fe7d45SAlexander Motin 			}
186*43fe7d45SAlexander Motin 		}
187*43fe7d45SAlexander Motin 	}
188*43fe7d45SAlexander Motin 	statclockhandler(curthread->td_intr_frame);
189*43fe7d45SAlexander Motin }
190*43fe7d45SAlexander Motin 
191*43fe7d45SAlexander Motin /*
192*43fe7d45SAlexander Motin  * Check that both timers are running with at least 1/4 of configured rate.
193*43fe7d45SAlexander Motin  * If not - replace the broken one.
194*43fe7d45SAlexander Motin  */
195*43fe7d45SAlexander Motin static void
196*43fe7d45SAlexander Motin timercheck(void)
197*43fe7d45SAlexander Motin {
198*43fe7d45SAlexander Motin 
199*43fe7d45SAlexander Motin 	if (!timertest)
200*43fe7d45SAlexander Motin 		return;
201*43fe7d45SAlexander Motin 	timertest = 0;
202*43fe7d45SAlexander Motin 	if (timerticks[0] * 4 < timer1hz) {
203*43fe7d45SAlexander Motin 		printf("Event timer \"%s\" is dead.\n", timer[0]->et_name);
204*43fe7d45SAlexander Motin 		timer1hz = 0;
205*43fe7d45SAlexander Motin 		configtimer(0);
206*43fe7d45SAlexander Motin 		et_ban(timer[0]);
207*43fe7d45SAlexander Motin 		et_free(timer[0]);
208*43fe7d45SAlexander Motin 		timer[0] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
209*43fe7d45SAlexander Motin 		if (timer[0] == NULL) {
210*43fe7d45SAlexander Motin 			timer2hz = 0;
211*43fe7d45SAlexander Motin 			configtimer(1);
212*43fe7d45SAlexander Motin 			et_free(timer[1]);
213*43fe7d45SAlexander Motin 			timer[1] = NULL;
214*43fe7d45SAlexander Motin 			timer[0] = timer[1];
215*43fe7d45SAlexander Motin 		}
216*43fe7d45SAlexander Motin 		et_init(timer[0], timer1cb, NULL, NULL);
217*43fe7d45SAlexander Motin 		cpu_restartclocks();
218*43fe7d45SAlexander Motin 		return;
219*43fe7d45SAlexander Motin 	}
220*43fe7d45SAlexander Motin 	if (timerticks[1] * 4 < timer2hz) {
221*43fe7d45SAlexander Motin 		printf("Event timer \"%s\" is dead.\n", timer[1]->et_name);
222*43fe7d45SAlexander Motin 		timer2hz = 0;
223*43fe7d45SAlexander Motin 		configtimer(1);
224*43fe7d45SAlexander Motin 		et_ban(timer[1]);
225*43fe7d45SAlexander Motin 		et_free(timer[1]);
226*43fe7d45SAlexander Motin 		timer[1] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
227*43fe7d45SAlexander Motin 		if (timer[1] != NULL)
228*43fe7d45SAlexander Motin 			et_init(timer[1], timer2cb, NULL, NULL);
229*43fe7d45SAlexander Motin 		cpu_restartclocks();
230*43fe7d45SAlexander Motin 		return;
231*43fe7d45SAlexander Motin 	}
232*43fe7d45SAlexander Motin }
233*43fe7d45SAlexander Motin 
234*43fe7d45SAlexander Motin /*
235*43fe7d45SAlexander Motin  * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler.
236*43fe7d45SAlexander Motin  */
237*43fe7d45SAlexander Motin inline static int
238*43fe7d45SAlexander Motin doconfigtimer(int i)
239*43fe7d45SAlexander Motin {
240*43fe7d45SAlexander Motin 	tc *conf;
241*43fe7d45SAlexander Motin 
242*43fe7d45SAlexander Motin 	conf = DPCPU_PTR(configtimer);
243*43fe7d45SAlexander Motin 	if (atomic_load_acq_int(*conf + i)) {
244*43fe7d45SAlexander Motin 		if (i == 0 ? timer1hz : timer2hz)
245*43fe7d45SAlexander Motin 			et_start(timer[i], NULL, &timerperiod[i]);
246*43fe7d45SAlexander Motin 		else
247*43fe7d45SAlexander Motin 			et_stop(timer[i]);
248*43fe7d45SAlexander Motin 		atomic_store_rel_int(*conf + i, 0);
249*43fe7d45SAlexander Motin 		return (1);
250*43fe7d45SAlexander Motin 	}
251*43fe7d45SAlexander Motin 	return (0);
252*43fe7d45SAlexander Motin }
253*43fe7d45SAlexander Motin 
254*43fe7d45SAlexander Motin /*
255*43fe7d45SAlexander Motin  * Reconfigure specified timer.
256*43fe7d45SAlexander Motin  * For per-CPU timers use IPI to make other CPUs to reconfigure.
257*43fe7d45SAlexander Motin  */
258*43fe7d45SAlexander Motin static void
259*43fe7d45SAlexander Motin configtimer(int i)
260*43fe7d45SAlexander Motin {
261*43fe7d45SAlexander Motin #ifdef SMP
262*43fe7d45SAlexander Motin 	tc *conf;
263*43fe7d45SAlexander Motin 	int cpu;
264*43fe7d45SAlexander Motin 
265*43fe7d45SAlexander Motin 	critical_enter();
266*43fe7d45SAlexander Motin #endif
267*43fe7d45SAlexander Motin 	/* Start/stop global timer or per-CPU timer of this CPU. */
268*43fe7d45SAlexander Motin 	if (i == 0 ? timer1hz : timer2hz)
269*43fe7d45SAlexander Motin 		et_start(timer[i], NULL, &timerperiod[i]);
270*43fe7d45SAlexander Motin 	else
271*43fe7d45SAlexander Motin 		et_stop(timer[i]);
272*43fe7d45SAlexander Motin #ifdef SMP
273*43fe7d45SAlexander Motin 	if ((timer[i]->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) {
274*43fe7d45SAlexander Motin 		critical_exit();
275*43fe7d45SAlexander Motin 		return;
276*43fe7d45SAlexander Motin 	}
277*43fe7d45SAlexander Motin 	/* Set reconfigure flags for other CPUs. */
278*43fe7d45SAlexander Motin 	CPU_FOREACH(cpu) {
279*43fe7d45SAlexander Motin 		conf = DPCPU_ID_PTR(cpu, configtimer);
280*43fe7d45SAlexander Motin 		atomic_store_rel_int(*conf + i, (cpu == curcpu) ? 0 : 1);
281*43fe7d45SAlexander Motin 	}
282*43fe7d45SAlexander Motin 	/* Send reconfigure IPI. */
283*43fe7d45SAlexander Motin 	ipi_all_but_self(i == 0 ? IPI_HARDCLOCK : IPI_STATCLOCK);
284*43fe7d45SAlexander Motin 	/* Wait for reconfiguration completed. */
285*43fe7d45SAlexander Motin restart:
286*43fe7d45SAlexander Motin 	cpu_spinwait();
287*43fe7d45SAlexander Motin 	CPU_FOREACH(cpu) {
288*43fe7d45SAlexander Motin 		if (cpu == curcpu)
289*43fe7d45SAlexander Motin 			continue;
290*43fe7d45SAlexander Motin 		conf = DPCPU_ID_PTR(cpu, configtimer);
291*43fe7d45SAlexander Motin 		if (atomic_load_acq_int(*conf + i))
292*43fe7d45SAlexander Motin 			goto restart;
293*43fe7d45SAlexander Motin 	}
294*43fe7d45SAlexander Motin 	critical_exit();
295*43fe7d45SAlexander Motin #endif
296*43fe7d45SAlexander Motin }
297*43fe7d45SAlexander Motin 
298*43fe7d45SAlexander Motin /*
299*43fe7d45SAlexander Motin  * Configure and start event timers.
300*43fe7d45SAlexander Motin  */
301*43fe7d45SAlexander Motin void
302*43fe7d45SAlexander Motin cpu_initclocks_bsp(void)
303*43fe7d45SAlexander Motin {
304*43fe7d45SAlexander Motin 	int base, div;
305*43fe7d45SAlexander Motin 
306*43fe7d45SAlexander Motin 	timer[0] = et_find(timername[0], ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
307*43fe7d45SAlexander Motin 	if (timer[0] == NULL)
308*43fe7d45SAlexander Motin 		timer[0] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
309*43fe7d45SAlexander Motin 	if (timer[0] == NULL)
310*43fe7d45SAlexander Motin 		panic("No usable event timer found!");
311*43fe7d45SAlexander Motin 	et_init(timer[0], timer1cb, NULL, NULL);
312*43fe7d45SAlexander Motin 	timer[1] = et_find(timername[1][0] ? timername[1] : NULL,
313*43fe7d45SAlexander Motin 	    ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
314*43fe7d45SAlexander Motin 	if (timer[1])
315*43fe7d45SAlexander Motin 		et_init(timer[1], timer2cb, NULL, NULL);
316*43fe7d45SAlexander Motin 	/*
317*43fe7d45SAlexander Motin 	 * We honor the requested 'hz' value.
318*43fe7d45SAlexander Motin 	 * We want to run stathz in the neighborhood of 128hz.
319*43fe7d45SAlexander Motin 	 * We would like profhz to run as often as possible.
320*43fe7d45SAlexander Motin 	 */
321*43fe7d45SAlexander Motin 	if (singlemul == 0) {
322*43fe7d45SAlexander Motin 		if (hz >= 1500 || (hz % 128) == 0)
323*43fe7d45SAlexander Motin 			singlemul = 1;
324*43fe7d45SAlexander Motin 		else if (hz >= 750)
325*43fe7d45SAlexander Motin 			singlemul = 2;
326*43fe7d45SAlexander Motin 		else
327*43fe7d45SAlexander Motin 			singlemul = 4;
328*43fe7d45SAlexander Motin 	}
329*43fe7d45SAlexander Motin 	if (timer[1] == NULL) {
330*43fe7d45SAlexander Motin 		base = hz * singlemul;
331*43fe7d45SAlexander Motin 		if (base < 128)
332*43fe7d45SAlexander Motin 			stathz = base;
333*43fe7d45SAlexander Motin 		else {
334*43fe7d45SAlexander Motin 			div = base / 128;
335*43fe7d45SAlexander Motin 			if (div % 2 == 0)
336*43fe7d45SAlexander Motin 				div++;
337*43fe7d45SAlexander Motin 			stathz = base / div;
338*43fe7d45SAlexander Motin 		}
339*43fe7d45SAlexander Motin 		profhz = stathz;
340*43fe7d45SAlexander Motin 		while ((profhz + stathz) <= 8192)
341*43fe7d45SAlexander Motin 			profhz += stathz;
342*43fe7d45SAlexander Motin 	} else {
343*43fe7d45SAlexander Motin 		stathz = 128;
344*43fe7d45SAlexander Motin 		profhz = stathz * 64;
345*43fe7d45SAlexander Motin 	}
346*43fe7d45SAlexander Motin 	ET_LOCK();
347*43fe7d45SAlexander Motin 	cpu_restartclocks();
348*43fe7d45SAlexander Motin 	ET_UNLOCK();
349*43fe7d45SAlexander Motin }
350*43fe7d45SAlexander Motin 
351*43fe7d45SAlexander Motin /* Start per-CPU event timers on APs. */
352*43fe7d45SAlexander Motin void
353*43fe7d45SAlexander Motin cpu_initclocks_ap(void)
354*43fe7d45SAlexander Motin {
355*43fe7d45SAlexander Motin 
356*43fe7d45SAlexander Motin 	ET_LOCK();
357*43fe7d45SAlexander Motin 	if (timer[0]->et_flags & ET_FLAGS_PERCPU)
358*43fe7d45SAlexander Motin 		et_start(timer[0], NULL, &timerperiod[0]);
359*43fe7d45SAlexander Motin 	if (timer[1] && timer[1]->et_flags & ET_FLAGS_PERCPU)
360*43fe7d45SAlexander Motin 		et_start(timer[1], NULL, &timerperiod[1]);
361*43fe7d45SAlexander Motin 	ET_UNLOCK();
362*43fe7d45SAlexander Motin }
363*43fe7d45SAlexander Motin 
364*43fe7d45SAlexander Motin /* Reconfigure and restart event timers after configuration changes. */
365*43fe7d45SAlexander Motin static void
366*43fe7d45SAlexander Motin cpu_restartclocks(void)
367*43fe7d45SAlexander Motin {
368*43fe7d45SAlexander Motin 
369*43fe7d45SAlexander Motin 	/* Stop all event timers. */
370*43fe7d45SAlexander Motin 	timertest = 0;
371*43fe7d45SAlexander Motin 	if (timer1hz) {
372*43fe7d45SAlexander Motin 		timer1hz = 0;
373*43fe7d45SAlexander Motin 		configtimer(0);
374*43fe7d45SAlexander Motin 	}
375*43fe7d45SAlexander Motin 	if (timer[1] && timer2hz) {
376*43fe7d45SAlexander Motin 		timer2hz = 0;
377*43fe7d45SAlexander Motin 		configtimer(1);
378*43fe7d45SAlexander Motin 	}
379*43fe7d45SAlexander Motin 	/* Calculate new event timers parameters. */
380*43fe7d45SAlexander Motin 	if (timer[1] == NULL) {
381*43fe7d45SAlexander Motin 		timer1hz = hz * singlemul;
382*43fe7d45SAlexander Motin 		while (timer1hz < (profiling_on ? profhz : stathz))
383*43fe7d45SAlexander Motin 			timer1hz += hz;
384*43fe7d45SAlexander Motin 		timer2hz = 0;
385*43fe7d45SAlexander Motin 	} else {
386*43fe7d45SAlexander Motin 		timer1hz = hz;
387*43fe7d45SAlexander Motin 		timer2hz = profiling_on ? profhz : stathz;
388*43fe7d45SAlexander Motin 	}
389*43fe7d45SAlexander Motin 	printf("Starting kernel event timers: %s @ %dHz, %s @ %dHz\n",
390*43fe7d45SAlexander Motin 	    timer[0]->et_name, timer1hz,
391*43fe7d45SAlexander Motin 	    timer[1] ? timer[1]->et_name : "NONE", timer2hz);
392*43fe7d45SAlexander Motin 	/* Restart event timers. */
393*43fe7d45SAlexander Motin 	FREQ2BT(timer1hz, &timerperiod[0]);
394*43fe7d45SAlexander Motin 	configtimer(0);
395*43fe7d45SAlexander Motin 	if (timer[1]) {
396*43fe7d45SAlexander Motin 		timerticks[0] = 0;
397*43fe7d45SAlexander Motin 		timerticks[1] = 0;
398*43fe7d45SAlexander Motin 		FREQ2BT(timer2hz, &timerperiod[1]);
399*43fe7d45SAlexander Motin 		configtimer(1);
400*43fe7d45SAlexander Motin 		timertest = 1;
401*43fe7d45SAlexander Motin 	}
402*43fe7d45SAlexander Motin }
403*43fe7d45SAlexander Motin 
404*43fe7d45SAlexander Motin /* Switch to profiling clock rates. */
405*43fe7d45SAlexander Motin void
406*43fe7d45SAlexander Motin cpu_startprofclock(void)
407*43fe7d45SAlexander Motin {
408*43fe7d45SAlexander Motin 
409*43fe7d45SAlexander Motin 	ET_LOCK();
410*43fe7d45SAlexander Motin 	profiling_on = 1;
411*43fe7d45SAlexander Motin 	cpu_restartclocks();
412*43fe7d45SAlexander Motin 	ET_UNLOCK();
413*43fe7d45SAlexander Motin }
414*43fe7d45SAlexander Motin 
415*43fe7d45SAlexander Motin /* Switch to regular clock rates. */
416*43fe7d45SAlexander Motin void
417*43fe7d45SAlexander Motin cpu_stopprofclock(void)
418*43fe7d45SAlexander Motin {
419*43fe7d45SAlexander Motin 
420*43fe7d45SAlexander Motin 	ET_LOCK();
421*43fe7d45SAlexander Motin 	profiling_on = 0;
422*43fe7d45SAlexander Motin 	cpu_restartclocks();
423*43fe7d45SAlexander Motin 	ET_UNLOCK();
424*43fe7d45SAlexander Motin }
425*43fe7d45SAlexander Motin 
426*43fe7d45SAlexander Motin /* Report or change the active event timers hardware. */
427*43fe7d45SAlexander Motin static int
428*43fe7d45SAlexander Motin sysctl_kern_eventtimer_timer1(SYSCTL_HANDLER_ARGS)
429*43fe7d45SAlexander Motin {
430*43fe7d45SAlexander Motin 	char buf[32];
431*43fe7d45SAlexander Motin 	struct eventtimer *et;
432*43fe7d45SAlexander Motin 	int error;
433*43fe7d45SAlexander Motin 
434*43fe7d45SAlexander Motin 	ET_LOCK();
435*43fe7d45SAlexander Motin 	et = timer[0];
436*43fe7d45SAlexander Motin 	snprintf(buf, sizeof(buf), "%s", et->et_name);
437*43fe7d45SAlexander Motin 	ET_UNLOCK();
438*43fe7d45SAlexander Motin 	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
439*43fe7d45SAlexander Motin 	ET_LOCK();
440*43fe7d45SAlexander Motin 	et = timer[0];
441*43fe7d45SAlexander Motin 	if (error != 0 || req->newptr == NULL ||
442*43fe7d45SAlexander Motin 	    strcmp(buf, et->et_name) == 0) {
443*43fe7d45SAlexander Motin 		ET_UNLOCK();
444*43fe7d45SAlexander Motin 		return (error);
445*43fe7d45SAlexander Motin 	}
446*43fe7d45SAlexander Motin 	et = et_find(buf, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
447*43fe7d45SAlexander Motin 	if (et == NULL) {
448*43fe7d45SAlexander Motin 		ET_UNLOCK();
449*43fe7d45SAlexander Motin 		return (ENOENT);
450*43fe7d45SAlexander Motin 	}
451*43fe7d45SAlexander Motin 	timer1hz = 0;
452*43fe7d45SAlexander Motin 	configtimer(0);
453*43fe7d45SAlexander Motin 	et_free(timer[0]);
454*43fe7d45SAlexander Motin 	timer[0] = et;
455*43fe7d45SAlexander Motin 	et_init(timer[0], timer1cb, NULL, NULL);
456*43fe7d45SAlexander Motin 	cpu_restartclocks();
457*43fe7d45SAlexander Motin 	ET_UNLOCK();
458*43fe7d45SAlexander Motin 	return (error);
459*43fe7d45SAlexander Motin }
460*43fe7d45SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer1,
461*43fe7d45SAlexander Motin     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
462*43fe7d45SAlexander Motin     0, 0, sysctl_kern_eventtimer_timer1, "A", "Primary event timer");
463*43fe7d45SAlexander Motin 
464*43fe7d45SAlexander Motin static int
465*43fe7d45SAlexander Motin sysctl_kern_eventtimer_timer2(SYSCTL_HANDLER_ARGS)
466*43fe7d45SAlexander Motin {
467*43fe7d45SAlexander Motin 	char buf[32];
468*43fe7d45SAlexander Motin 	struct eventtimer *et;
469*43fe7d45SAlexander Motin 	int error;
470*43fe7d45SAlexander Motin 
471*43fe7d45SAlexander Motin 	ET_LOCK();
472*43fe7d45SAlexander Motin 	et = timer[1];
473*43fe7d45SAlexander Motin 	if (et == NULL)
474*43fe7d45SAlexander Motin 		snprintf(buf, sizeof(buf), "NONE");
475*43fe7d45SAlexander Motin 	else
476*43fe7d45SAlexander Motin 		snprintf(buf, sizeof(buf), "%s", et->et_name);
477*43fe7d45SAlexander Motin 	ET_UNLOCK();
478*43fe7d45SAlexander Motin 	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
479*43fe7d45SAlexander Motin 	ET_LOCK();
480*43fe7d45SAlexander Motin 	et = timer[1];
481*43fe7d45SAlexander Motin 	if (error != 0 || req->newptr == NULL ||
482*43fe7d45SAlexander Motin 	    strcmp(buf, et ? et->et_name : "NONE") == 0) {
483*43fe7d45SAlexander Motin 		ET_UNLOCK();
484*43fe7d45SAlexander Motin 		return (error);
485*43fe7d45SAlexander Motin 	}
486*43fe7d45SAlexander Motin 	et = et_find(buf, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
487*43fe7d45SAlexander Motin 	if (et == NULL && strcasecmp(buf, "NONE") != 0) {
488*43fe7d45SAlexander Motin 		ET_UNLOCK();
489*43fe7d45SAlexander Motin 		return (ENOENT);
490*43fe7d45SAlexander Motin 	}
491*43fe7d45SAlexander Motin 	if (timer[1] != NULL) {
492*43fe7d45SAlexander Motin 		timer2hz = 0;
493*43fe7d45SAlexander Motin 		configtimer(1);
494*43fe7d45SAlexander Motin 		et_free(timer[1]);
495*43fe7d45SAlexander Motin 	}
496*43fe7d45SAlexander Motin 	timer[1] = et;
497*43fe7d45SAlexander Motin 	if (timer[1] != NULL)
498*43fe7d45SAlexander Motin 		et_init(timer[1], timer2cb, NULL, NULL);
499*43fe7d45SAlexander Motin 	cpu_restartclocks();
500*43fe7d45SAlexander Motin 	ET_UNLOCK();
501*43fe7d45SAlexander Motin 	return (error);
502*43fe7d45SAlexander Motin }
503*43fe7d45SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer2,
504*43fe7d45SAlexander Motin     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
505*43fe7d45SAlexander Motin     0, 0, sysctl_kern_eventtimer_timer2, "A", "Secondary event timer");
506*43fe7d45SAlexander Motin 
507*43fe7d45SAlexander Motin #endif
508*43fe7d45SAlexander Motin 
509