xref: /freebsd/sys/kern/kern_clocksource.c (revision 51636352b6292085217039c4feaf710064a53add)
143fe7d45SAlexander Motin /*-
243fe7d45SAlexander Motin  * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
343fe7d45SAlexander Motin  * All rights reserved.
443fe7d45SAlexander Motin  *
543fe7d45SAlexander Motin  * Redistribution and use in source and binary forms, with or without
643fe7d45SAlexander Motin  * modification, are permitted provided that the following conditions
743fe7d45SAlexander Motin  * are met:
843fe7d45SAlexander Motin  * 1. Redistributions of source code must retain the above copyright
943fe7d45SAlexander Motin  *    notice, this list of conditions and the following disclaimer,
1043fe7d45SAlexander Motin  *    without modification, immediately at the beginning of the file.
1143fe7d45SAlexander Motin  * 2. Redistributions in binary form must reproduce the above copyright
1243fe7d45SAlexander Motin  *    notice, this list of conditions and the following disclaimer in the
1343fe7d45SAlexander Motin  *    documentation and/or other materials provided with the distribution.
1443fe7d45SAlexander Motin  *
1543fe7d45SAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1643fe7d45SAlexander Motin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1743fe7d45SAlexander Motin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1843fe7d45SAlexander Motin  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1943fe7d45SAlexander Motin  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2043fe7d45SAlexander Motin  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2143fe7d45SAlexander Motin  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2243fe7d45SAlexander Motin  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2343fe7d45SAlexander Motin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2443fe7d45SAlexander Motin  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2543fe7d45SAlexander Motin  */
2643fe7d45SAlexander Motin 
2743fe7d45SAlexander Motin #include <sys/cdefs.h>
2843fe7d45SAlexander Motin __FBSDID("$FreeBSD$");
2943fe7d45SAlexander Motin 
3043fe7d45SAlexander Motin /*
3143fe7d45SAlexander Motin  * Common routines to manage event timers hardware.
3243fe7d45SAlexander Motin  */
3343fe7d45SAlexander Motin 
3443fe7d45SAlexander Motin /* XEN has own timer routines now. */
3543fe7d45SAlexander Motin #ifndef XEN
3643fe7d45SAlexander Motin 
3743fe7d45SAlexander Motin #include "opt_kdtrace.h"
3843fe7d45SAlexander Motin 
3943fe7d45SAlexander Motin #include <sys/param.h>
4043fe7d45SAlexander Motin #include <sys/systm.h>
4143fe7d45SAlexander Motin #include <sys/bus.h>
4243fe7d45SAlexander Motin #include <sys/lock.h>
4343fe7d45SAlexander Motin #include <sys/kdb.h>
4443fe7d45SAlexander Motin #include <sys/mutex.h>
4543fe7d45SAlexander Motin #include <sys/proc.h>
4643fe7d45SAlexander Motin #include <sys/kernel.h>
4743fe7d45SAlexander Motin #include <sys/sched.h>
4843fe7d45SAlexander Motin #include <sys/smp.h>
4943fe7d45SAlexander Motin #include <sys/sysctl.h>
5043fe7d45SAlexander Motin #include <sys/timeet.h>
5143fe7d45SAlexander Motin 
5243fe7d45SAlexander Motin #include <machine/atomic.h>
5343fe7d45SAlexander Motin #include <machine/clock.h>
5443fe7d45SAlexander Motin #include <machine/cpu.h>
5543fe7d45SAlexander Motin #include <machine/smp.h>
5643fe7d45SAlexander Motin 
5743fe7d45SAlexander Motin #ifdef KDTRACE_HOOKS
5843fe7d45SAlexander Motin #include <sys/dtrace_bsd.h>
5943fe7d45SAlexander Motin cyclic_clock_func_t	cyclic_clock_func[MAXCPU];
6043fe7d45SAlexander Motin #endif
6143fe7d45SAlexander Motin 
6243fe7d45SAlexander Motin static void		cpu_restartclocks(void);
6343fe7d45SAlexander Motin static void		timercheck(void);
6443fe7d45SAlexander Motin inline static int	doconfigtimer(int i);
6543fe7d45SAlexander Motin static void		configtimer(int i);
6643fe7d45SAlexander Motin 
6743fe7d45SAlexander Motin static struct eventtimer *timer[2] = { NULL, NULL };
6843fe7d45SAlexander Motin static int		timertest = 0;
6943fe7d45SAlexander Motin static int		timerticks[2] = { 0, 0 };
7043fe7d45SAlexander Motin static int		profiling_on = 0;
7143fe7d45SAlexander Motin static struct bintime	timerperiod[2];
7243fe7d45SAlexander Motin 
7343fe7d45SAlexander Motin static char		timername[2][32];
7443fe7d45SAlexander Motin TUNABLE_STR("kern.eventtimer.timer1", timername[0], sizeof(*timername));
7543fe7d45SAlexander Motin TUNABLE_STR("kern.eventtimer.timer2", timername[1], sizeof(*timername));
7643fe7d45SAlexander Motin 
7743fe7d45SAlexander Motin static u_int		singlemul = 0;
7843fe7d45SAlexander Motin TUNABLE_INT("kern.eventtimer.singlemul", &singlemul);
7943fe7d45SAlexander Motin SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul,
8043fe7d45SAlexander Motin     0, "Multiplier, used in single timer mode");
8143fe7d45SAlexander Motin 
8243fe7d45SAlexander Motin typedef u_int tc[2];
8343fe7d45SAlexander Motin static DPCPU_DEFINE(tc, configtimer);
8443fe7d45SAlexander Motin 
8543fe7d45SAlexander Motin #define FREQ2BT(freq, bt)						\
8643fe7d45SAlexander Motin {									\
8743fe7d45SAlexander Motin 	(bt)->sec = 0;							\
8843fe7d45SAlexander Motin 	(bt)->frac = ((uint64_t)0x8000000000000000  / (freq)) << 1;	\
8943fe7d45SAlexander Motin }
90*51636352SAlexander Motin #define BT2FREQ(bt)							\
91*51636352SAlexander Motin 	(((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) /		\
92*51636352SAlexander Motin 	    ((bt)->frac >> 1))
9343fe7d45SAlexander Motin 
9443fe7d45SAlexander Motin /* Per-CPU timer1 handler. */
9543fe7d45SAlexander Motin static int
9643fe7d45SAlexander Motin hardclockhandler(struct trapframe *frame)
9743fe7d45SAlexander Motin {
9843fe7d45SAlexander Motin 
9943fe7d45SAlexander Motin #ifdef KDTRACE_HOOKS
10043fe7d45SAlexander Motin 	/*
10143fe7d45SAlexander Motin 	 * If the DTrace hooks are configured and a callback function
10243fe7d45SAlexander Motin 	 * has been registered, then call it to process the high speed
10343fe7d45SAlexander Motin 	 * timers.
10443fe7d45SAlexander Motin 	 */
10543fe7d45SAlexander Motin 	int cpu = curcpu;
10643fe7d45SAlexander Motin 	if (cyclic_clock_func[cpu] != NULL)
10743fe7d45SAlexander Motin 		(*cyclic_clock_func[cpu])(frame);
10843fe7d45SAlexander Motin #endif
10943fe7d45SAlexander Motin 
11043fe7d45SAlexander Motin 	timer1clock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
11143fe7d45SAlexander Motin 	return (FILTER_HANDLED);
11243fe7d45SAlexander Motin }
11343fe7d45SAlexander Motin 
11443fe7d45SAlexander Motin /* Per-CPU timer2 handler. */
11543fe7d45SAlexander Motin static int
11643fe7d45SAlexander Motin statclockhandler(struct trapframe *frame)
11743fe7d45SAlexander Motin {
11843fe7d45SAlexander Motin 
11943fe7d45SAlexander Motin 	timer2clock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
12043fe7d45SAlexander Motin 	return (FILTER_HANDLED);
12143fe7d45SAlexander Motin }
12243fe7d45SAlexander Motin 
12343fe7d45SAlexander Motin /* timer1 broadcast IPI handler. */
12443fe7d45SAlexander Motin int
12543fe7d45SAlexander Motin hardclockintr(struct trapframe *frame)
12643fe7d45SAlexander Motin {
12743fe7d45SAlexander Motin 
12843fe7d45SAlexander Motin 	if (doconfigtimer(0))
12943fe7d45SAlexander Motin 		return (FILTER_HANDLED);
13043fe7d45SAlexander Motin 	return (hardclockhandler(frame));
13143fe7d45SAlexander Motin }
13243fe7d45SAlexander Motin 
13343fe7d45SAlexander Motin /* timer2 broadcast IPI handler. */
13443fe7d45SAlexander Motin int
13543fe7d45SAlexander Motin statclockintr(struct trapframe *frame)
13643fe7d45SAlexander Motin {
13743fe7d45SAlexander Motin 
13843fe7d45SAlexander Motin 	if (doconfigtimer(1))
13943fe7d45SAlexander Motin 		return (FILTER_HANDLED);
14043fe7d45SAlexander Motin 	return (statclockhandler(frame));
14143fe7d45SAlexander Motin }
14243fe7d45SAlexander Motin 
14343fe7d45SAlexander Motin /* timer1 callback. */
14443fe7d45SAlexander Motin static void
14543fe7d45SAlexander Motin timer1cb(struct eventtimer *et, void *arg)
14643fe7d45SAlexander Motin {
14743fe7d45SAlexander Motin 
14843fe7d45SAlexander Motin #ifdef SMP
14943fe7d45SAlexander Motin 	/* Broadcast interrupt to other CPUs for non-per-CPU timers */
15043fe7d45SAlexander Motin 	if (smp_started && (et->et_flags & ET_FLAGS_PERCPU) == 0)
15143fe7d45SAlexander Motin 		ipi_all_but_self(IPI_HARDCLOCK);
15243fe7d45SAlexander Motin #endif
15343fe7d45SAlexander Motin 	if (timertest) {
15443fe7d45SAlexander Motin 		if ((et->et_flags & ET_FLAGS_PERCPU) == 0 || curcpu == 0) {
15543fe7d45SAlexander Motin 			timerticks[0]++;
15643fe7d45SAlexander Motin 			if (timerticks[0] >= timer1hz) {
15743fe7d45SAlexander Motin 				ET_LOCK();
15843fe7d45SAlexander Motin 				timercheck();
15943fe7d45SAlexander Motin 				ET_UNLOCK();
16043fe7d45SAlexander Motin 			}
16143fe7d45SAlexander Motin 		}
16243fe7d45SAlexander Motin 	}
16343fe7d45SAlexander Motin 	hardclockhandler(curthread->td_intr_frame);
16443fe7d45SAlexander Motin }
16543fe7d45SAlexander Motin 
16643fe7d45SAlexander Motin /* timer2 callback. */
16743fe7d45SAlexander Motin static void
16843fe7d45SAlexander Motin timer2cb(struct eventtimer *et, void *arg)
16943fe7d45SAlexander Motin {
17043fe7d45SAlexander Motin 
17143fe7d45SAlexander Motin #ifdef SMP
17243fe7d45SAlexander Motin 	/* Broadcast interrupt to other CPUs for non-per-CPU timers */
17343fe7d45SAlexander Motin 	if (smp_started && (et->et_flags & ET_FLAGS_PERCPU) == 0)
17443fe7d45SAlexander Motin 		ipi_all_but_self(IPI_STATCLOCK);
17543fe7d45SAlexander Motin #endif
17643fe7d45SAlexander Motin 	if (timertest) {
17743fe7d45SAlexander Motin 		if ((et->et_flags & ET_FLAGS_PERCPU) == 0 || curcpu == 0) {
17843fe7d45SAlexander Motin 			timerticks[1]++;
17943fe7d45SAlexander Motin 			if (timerticks[1] >= timer2hz * 2) {
18043fe7d45SAlexander Motin 				ET_LOCK();
18143fe7d45SAlexander Motin 				timercheck();
18243fe7d45SAlexander Motin 				ET_UNLOCK();
18343fe7d45SAlexander Motin 			}
18443fe7d45SAlexander Motin 		}
18543fe7d45SAlexander Motin 	}
18643fe7d45SAlexander Motin 	statclockhandler(curthread->td_intr_frame);
18743fe7d45SAlexander Motin }
18843fe7d45SAlexander Motin 
18943fe7d45SAlexander Motin /*
19043fe7d45SAlexander Motin  * Check that both timers are running with at least 1/4 of configured rate.
19143fe7d45SAlexander Motin  * If not - replace the broken one.
19243fe7d45SAlexander Motin  */
19343fe7d45SAlexander Motin static void
19443fe7d45SAlexander Motin timercheck(void)
19543fe7d45SAlexander Motin {
19643fe7d45SAlexander Motin 
19743fe7d45SAlexander Motin 	if (!timertest)
19843fe7d45SAlexander Motin 		return;
19943fe7d45SAlexander Motin 	timertest = 0;
20043fe7d45SAlexander Motin 	if (timerticks[0] * 4 < timer1hz) {
20143fe7d45SAlexander Motin 		printf("Event timer \"%s\" is dead.\n", timer[0]->et_name);
20243fe7d45SAlexander Motin 		timer1hz = 0;
20343fe7d45SAlexander Motin 		configtimer(0);
20443fe7d45SAlexander Motin 		et_ban(timer[0]);
20543fe7d45SAlexander Motin 		et_free(timer[0]);
20643fe7d45SAlexander Motin 		timer[0] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
20743fe7d45SAlexander Motin 		if (timer[0] == NULL) {
20843fe7d45SAlexander Motin 			timer2hz = 0;
20943fe7d45SAlexander Motin 			configtimer(1);
21043fe7d45SAlexander Motin 			et_free(timer[1]);
21143fe7d45SAlexander Motin 			timer[1] = NULL;
21243fe7d45SAlexander Motin 			timer[0] = timer[1];
21343fe7d45SAlexander Motin 		}
21443fe7d45SAlexander Motin 		et_init(timer[0], timer1cb, NULL, NULL);
21543fe7d45SAlexander Motin 		cpu_restartclocks();
21643fe7d45SAlexander Motin 		return;
21743fe7d45SAlexander Motin 	}
21843fe7d45SAlexander Motin 	if (timerticks[1] * 4 < timer2hz) {
21943fe7d45SAlexander Motin 		printf("Event timer \"%s\" is dead.\n", timer[1]->et_name);
22043fe7d45SAlexander Motin 		timer2hz = 0;
22143fe7d45SAlexander Motin 		configtimer(1);
22243fe7d45SAlexander Motin 		et_ban(timer[1]);
22343fe7d45SAlexander Motin 		et_free(timer[1]);
22443fe7d45SAlexander Motin 		timer[1] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
22543fe7d45SAlexander Motin 		if (timer[1] != NULL)
22643fe7d45SAlexander Motin 			et_init(timer[1], timer2cb, NULL, NULL);
22743fe7d45SAlexander Motin 		cpu_restartclocks();
22843fe7d45SAlexander Motin 		return;
22943fe7d45SAlexander Motin 	}
23043fe7d45SAlexander Motin }
23143fe7d45SAlexander Motin 
23243fe7d45SAlexander Motin /*
23343fe7d45SAlexander Motin  * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler.
23443fe7d45SAlexander Motin  */
23543fe7d45SAlexander Motin inline static int
23643fe7d45SAlexander Motin doconfigtimer(int i)
23743fe7d45SAlexander Motin {
23843fe7d45SAlexander Motin 	tc *conf;
23943fe7d45SAlexander Motin 
24043fe7d45SAlexander Motin 	conf = DPCPU_PTR(configtimer);
24143fe7d45SAlexander Motin 	if (atomic_load_acq_int(*conf + i)) {
24243fe7d45SAlexander Motin 		if (i == 0 ? timer1hz : timer2hz)
24343fe7d45SAlexander Motin 			et_start(timer[i], NULL, &timerperiod[i]);
24443fe7d45SAlexander Motin 		else
24543fe7d45SAlexander Motin 			et_stop(timer[i]);
24643fe7d45SAlexander Motin 		atomic_store_rel_int(*conf + i, 0);
24743fe7d45SAlexander Motin 		return (1);
24843fe7d45SAlexander Motin 	}
24943fe7d45SAlexander Motin 	return (0);
25043fe7d45SAlexander Motin }
25143fe7d45SAlexander Motin 
25243fe7d45SAlexander Motin /*
25343fe7d45SAlexander Motin  * Reconfigure specified timer.
25443fe7d45SAlexander Motin  * For per-CPU timers use IPI to make other CPUs to reconfigure.
25543fe7d45SAlexander Motin  */
25643fe7d45SAlexander Motin static void
25743fe7d45SAlexander Motin configtimer(int i)
25843fe7d45SAlexander Motin {
25943fe7d45SAlexander Motin #ifdef SMP
26043fe7d45SAlexander Motin 	tc *conf;
26143fe7d45SAlexander Motin 	int cpu;
26243fe7d45SAlexander Motin 
26343fe7d45SAlexander Motin 	critical_enter();
26443fe7d45SAlexander Motin #endif
26543fe7d45SAlexander Motin 	/* Start/stop global timer or per-CPU timer of this CPU. */
26643fe7d45SAlexander Motin 	if (i == 0 ? timer1hz : timer2hz)
26743fe7d45SAlexander Motin 		et_start(timer[i], NULL, &timerperiod[i]);
26843fe7d45SAlexander Motin 	else
26943fe7d45SAlexander Motin 		et_stop(timer[i]);
27043fe7d45SAlexander Motin #ifdef SMP
27143fe7d45SAlexander Motin 	if ((timer[i]->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) {
27243fe7d45SAlexander Motin 		critical_exit();
27343fe7d45SAlexander Motin 		return;
27443fe7d45SAlexander Motin 	}
27543fe7d45SAlexander Motin 	/* Set reconfigure flags for other CPUs. */
27643fe7d45SAlexander Motin 	CPU_FOREACH(cpu) {
27743fe7d45SAlexander Motin 		conf = DPCPU_ID_PTR(cpu, configtimer);
27843fe7d45SAlexander Motin 		atomic_store_rel_int(*conf + i, (cpu == curcpu) ? 0 : 1);
27943fe7d45SAlexander Motin 	}
28043fe7d45SAlexander Motin 	/* Send reconfigure IPI. */
28143fe7d45SAlexander Motin 	ipi_all_but_self(i == 0 ? IPI_HARDCLOCK : IPI_STATCLOCK);
28243fe7d45SAlexander Motin 	/* Wait for reconfiguration completed. */
28343fe7d45SAlexander Motin restart:
28443fe7d45SAlexander Motin 	cpu_spinwait();
28543fe7d45SAlexander Motin 	CPU_FOREACH(cpu) {
28643fe7d45SAlexander Motin 		if (cpu == curcpu)
28743fe7d45SAlexander Motin 			continue;
28843fe7d45SAlexander Motin 		conf = DPCPU_ID_PTR(cpu, configtimer);
28943fe7d45SAlexander Motin 		if (atomic_load_acq_int(*conf + i))
29043fe7d45SAlexander Motin 			goto restart;
29143fe7d45SAlexander Motin 	}
29243fe7d45SAlexander Motin 	critical_exit();
29343fe7d45SAlexander Motin #endif
29443fe7d45SAlexander Motin }
29543fe7d45SAlexander Motin 
296*51636352SAlexander Motin static int
297*51636352SAlexander Motin round_freq(struct eventtimer *et, int freq)
298*51636352SAlexander Motin {
299*51636352SAlexander Motin 	uint64_t div;
300*51636352SAlexander Motin 
301*51636352SAlexander Motin 	if (et->et_frequency != 0) {
302*51636352SAlexander Motin 		div = (et->et_frequency + freq / 2) / freq;
303*51636352SAlexander Motin 		if (et->et_flags & ET_FLAGS_POW2DIV)
304*51636352SAlexander Motin 			div = 1 << (flsl(div + div / 2) - 1);
305*51636352SAlexander Motin 		freq = (et->et_frequency + div / 2) / div;
306*51636352SAlexander Motin 	}
307*51636352SAlexander Motin 	if (et->et_min_period.sec > 0)
308*51636352SAlexander Motin 		freq = 0;
309*51636352SAlexander Motin 	else if (et->et_max_period.frac != 0)
310*51636352SAlexander Motin 		freq = min(freq, BT2FREQ(&et->et_min_period));
311*51636352SAlexander Motin 	if (et->et_max_period.sec == 0 && et->et_max_period.frac != 0)
312*51636352SAlexander Motin 		freq = max(freq, BT2FREQ(&et->et_max_period));
313*51636352SAlexander Motin 	return (freq);
314*51636352SAlexander Motin }
315*51636352SAlexander Motin 
31643fe7d45SAlexander Motin /*
31743fe7d45SAlexander Motin  * Configure and start event timers.
31843fe7d45SAlexander Motin  */
31943fe7d45SAlexander Motin void
32043fe7d45SAlexander Motin cpu_initclocks_bsp(void)
32143fe7d45SAlexander Motin {
32243fe7d45SAlexander Motin 	int base, div;
32343fe7d45SAlexander Motin 
32443fe7d45SAlexander Motin 	timer[0] = et_find(timername[0], ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
32543fe7d45SAlexander Motin 	if (timer[0] == NULL)
32643fe7d45SAlexander Motin 		timer[0] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
32743fe7d45SAlexander Motin 	if (timer[0] == NULL)
32843fe7d45SAlexander Motin 		panic("No usable event timer found!");
32943fe7d45SAlexander Motin 	et_init(timer[0], timer1cb, NULL, NULL);
33043fe7d45SAlexander Motin 	timer[1] = et_find(timername[1][0] ? timername[1] : NULL,
33143fe7d45SAlexander Motin 	    ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
33243fe7d45SAlexander Motin 	if (timer[1])
33343fe7d45SAlexander Motin 		et_init(timer[1], timer2cb, NULL, NULL);
33443fe7d45SAlexander Motin 	/*
33543fe7d45SAlexander Motin 	 * We honor the requested 'hz' value.
33643fe7d45SAlexander Motin 	 * We want to run stathz in the neighborhood of 128hz.
33743fe7d45SAlexander Motin 	 * We would like profhz to run as often as possible.
33843fe7d45SAlexander Motin 	 */
33943fe7d45SAlexander Motin 	if (singlemul == 0) {
34043fe7d45SAlexander Motin 		if (hz >= 1500 || (hz % 128) == 0)
34143fe7d45SAlexander Motin 			singlemul = 1;
34243fe7d45SAlexander Motin 		else if (hz >= 750)
34343fe7d45SAlexander Motin 			singlemul = 2;
34443fe7d45SAlexander Motin 		else
34543fe7d45SAlexander Motin 			singlemul = 4;
34643fe7d45SAlexander Motin 	}
34743fe7d45SAlexander Motin 	if (timer[1] == NULL) {
348*51636352SAlexander Motin 		base = round_freq(timer[0], hz * singlemul);
349*51636352SAlexander Motin 		singlemul = max((base + hz / 2) / hz, 1);
350*51636352SAlexander Motin 		hz = (base + singlemul / 2) / singlemul;
351*51636352SAlexander Motin 		if (base <= 128)
35243fe7d45SAlexander Motin 			stathz = base;
35343fe7d45SAlexander Motin 		else {
35443fe7d45SAlexander Motin 			div = base / 128;
355*51636352SAlexander Motin 			if (div >= singlemul && (div % singlemul) == 0)
35643fe7d45SAlexander Motin 				div++;
35743fe7d45SAlexander Motin 			stathz = base / div;
35843fe7d45SAlexander Motin 		}
35943fe7d45SAlexander Motin 		profhz = stathz;
360*51636352SAlexander Motin 		while ((profhz + stathz) <= 128 * 64)
36143fe7d45SAlexander Motin 			profhz += stathz;
362*51636352SAlexander Motin 		profhz = round_freq(timer[0], profhz);
36343fe7d45SAlexander Motin 	} else {
364*51636352SAlexander Motin 		hz = round_freq(timer[0], hz);
365*51636352SAlexander Motin 		stathz = round_freq(timer[1], 127);
366*51636352SAlexander Motin 		profhz = round_freq(timer[1], stathz * 64);
36743fe7d45SAlexander Motin 	}
36843fe7d45SAlexander Motin 	ET_LOCK();
36943fe7d45SAlexander Motin 	cpu_restartclocks();
37043fe7d45SAlexander Motin 	ET_UNLOCK();
37143fe7d45SAlexander Motin }
37243fe7d45SAlexander Motin 
37343fe7d45SAlexander Motin /* Start per-CPU event timers on APs. */
37443fe7d45SAlexander Motin void
37543fe7d45SAlexander Motin cpu_initclocks_ap(void)
37643fe7d45SAlexander Motin {
37743fe7d45SAlexander Motin 
37843fe7d45SAlexander Motin 	ET_LOCK();
37943fe7d45SAlexander Motin 	if (timer[0]->et_flags & ET_FLAGS_PERCPU)
38043fe7d45SAlexander Motin 		et_start(timer[0], NULL, &timerperiod[0]);
38143fe7d45SAlexander Motin 	if (timer[1] && timer[1]->et_flags & ET_FLAGS_PERCPU)
38243fe7d45SAlexander Motin 		et_start(timer[1], NULL, &timerperiod[1]);
38343fe7d45SAlexander Motin 	ET_UNLOCK();
38443fe7d45SAlexander Motin }
38543fe7d45SAlexander Motin 
38643fe7d45SAlexander Motin /* Reconfigure and restart event timers after configuration changes. */
38743fe7d45SAlexander Motin static void
38843fe7d45SAlexander Motin cpu_restartclocks(void)
38943fe7d45SAlexander Motin {
39043fe7d45SAlexander Motin 
39143fe7d45SAlexander Motin 	/* Stop all event timers. */
39243fe7d45SAlexander Motin 	timertest = 0;
39343fe7d45SAlexander Motin 	if (timer1hz) {
39443fe7d45SAlexander Motin 		timer1hz = 0;
39543fe7d45SAlexander Motin 		configtimer(0);
39643fe7d45SAlexander Motin 	}
39743fe7d45SAlexander Motin 	if (timer[1] && timer2hz) {
39843fe7d45SAlexander Motin 		timer2hz = 0;
39943fe7d45SAlexander Motin 		configtimer(1);
40043fe7d45SAlexander Motin 	}
40143fe7d45SAlexander Motin 	/* Calculate new event timers parameters. */
40243fe7d45SAlexander Motin 	if (timer[1] == NULL) {
40343fe7d45SAlexander Motin 		timer1hz = hz * singlemul;
40443fe7d45SAlexander Motin 		while (timer1hz < (profiling_on ? profhz : stathz))
40543fe7d45SAlexander Motin 			timer1hz += hz;
40643fe7d45SAlexander Motin 		timer2hz = 0;
40743fe7d45SAlexander Motin 	} else {
40843fe7d45SAlexander Motin 		timer1hz = hz;
40943fe7d45SAlexander Motin 		timer2hz = profiling_on ? profhz : stathz;
410*51636352SAlexander Motin 		timer2hz = round_freq(timer[1], timer2hz);
41143fe7d45SAlexander Motin 	}
412*51636352SAlexander Motin 	timer1hz = round_freq(timer[0], timer1hz);
41343fe7d45SAlexander Motin 	printf("Starting kernel event timers: %s @ %dHz, %s @ %dHz\n",
41443fe7d45SAlexander Motin 	    timer[0]->et_name, timer1hz,
41543fe7d45SAlexander Motin 	    timer[1] ? timer[1]->et_name : "NONE", timer2hz);
41643fe7d45SAlexander Motin 	/* Restart event timers. */
41743fe7d45SAlexander Motin 	FREQ2BT(timer1hz, &timerperiod[0]);
41843fe7d45SAlexander Motin 	configtimer(0);
41943fe7d45SAlexander Motin 	if (timer[1]) {
42043fe7d45SAlexander Motin 		timerticks[0] = 0;
42143fe7d45SAlexander Motin 		timerticks[1] = 0;
42243fe7d45SAlexander Motin 		FREQ2BT(timer2hz, &timerperiod[1]);
42343fe7d45SAlexander Motin 		configtimer(1);
42443fe7d45SAlexander Motin 		timertest = 1;
42543fe7d45SAlexander Motin 	}
42643fe7d45SAlexander Motin }
42743fe7d45SAlexander Motin 
42843fe7d45SAlexander Motin /* Switch to profiling clock rates. */
42943fe7d45SAlexander Motin void
43043fe7d45SAlexander Motin cpu_startprofclock(void)
43143fe7d45SAlexander Motin {
43243fe7d45SAlexander Motin 
43343fe7d45SAlexander Motin 	ET_LOCK();
43443fe7d45SAlexander Motin 	profiling_on = 1;
43543fe7d45SAlexander Motin 	cpu_restartclocks();
43643fe7d45SAlexander Motin 	ET_UNLOCK();
43743fe7d45SAlexander Motin }
43843fe7d45SAlexander Motin 
43943fe7d45SAlexander Motin /* Switch to regular clock rates. */
44043fe7d45SAlexander Motin void
44143fe7d45SAlexander Motin cpu_stopprofclock(void)
44243fe7d45SAlexander Motin {
44343fe7d45SAlexander Motin 
44443fe7d45SAlexander Motin 	ET_LOCK();
44543fe7d45SAlexander Motin 	profiling_on = 0;
44643fe7d45SAlexander Motin 	cpu_restartclocks();
44743fe7d45SAlexander Motin 	ET_UNLOCK();
44843fe7d45SAlexander Motin }
44943fe7d45SAlexander Motin 
45043fe7d45SAlexander Motin /* Report or change the active event timers hardware. */
45143fe7d45SAlexander Motin static int
45243fe7d45SAlexander Motin sysctl_kern_eventtimer_timer1(SYSCTL_HANDLER_ARGS)
45343fe7d45SAlexander Motin {
45443fe7d45SAlexander Motin 	char buf[32];
45543fe7d45SAlexander Motin 	struct eventtimer *et;
45643fe7d45SAlexander Motin 	int error;
45743fe7d45SAlexander Motin 
45843fe7d45SAlexander Motin 	ET_LOCK();
45943fe7d45SAlexander Motin 	et = timer[0];
46043fe7d45SAlexander Motin 	snprintf(buf, sizeof(buf), "%s", et->et_name);
46143fe7d45SAlexander Motin 	ET_UNLOCK();
46243fe7d45SAlexander Motin 	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
46343fe7d45SAlexander Motin 	ET_LOCK();
46443fe7d45SAlexander Motin 	et = timer[0];
46543fe7d45SAlexander Motin 	if (error != 0 || req->newptr == NULL ||
46643fe7d45SAlexander Motin 	    strcmp(buf, et->et_name) == 0) {
46743fe7d45SAlexander Motin 		ET_UNLOCK();
46843fe7d45SAlexander Motin 		return (error);
46943fe7d45SAlexander Motin 	}
47043fe7d45SAlexander Motin 	et = et_find(buf, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
47143fe7d45SAlexander Motin 	if (et == NULL) {
47243fe7d45SAlexander Motin 		ET_UNLOCK();
47343fe7d45SAlexander Motin 		return (ENOENT);
47443fe7d45SAlexander Motin 	}
47543fe7d45SAlexander Motin 	timer1hz = 0;
47643fe7d45SAlexander Motin 	configtimer(0);
47743fe7d45SAlexander Motin 	et_free(timer[0]);
47843fe7d45SAlexander Motin 	timer[0] = et;
47943fe7d45SAlexander Motin 	et_init(timer[0], timer1cb, NULL, NULL);
48043fe7d45SAlexander Motin 	cpu_restartclocks();
48143fe7d45SAlexander Motin 	ET_UNLOCK();
48243fe7d45SAlexander Motin 	return (error);
48343fe7d45SAlexander Motin }
48443fe7d45SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer1,
48543fe7d45SAlexander Motin     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
48643fe7d45SAlexander Motin     0, 0, sysctl_kern_eventtimer_timer1, "A", "Primary event timer");
48743fe7d45SAlexander Motin 
48843fe7d45SAlexander Motin static int
48943fe7d45SAlexander Motin sysctl_kern_eventtimer_timer2(SYSCTL_HANDLER_ARGS)
49043fe7d45SAlexander Motin {
49143fe7d45SAlexander Motin 	char buf[32];
49243fe7d45SAlexander Motin 	struct eventtimer *et;
49343fe7d45SAlexander Motin 	int error;
49443fe7d45SAlexander Motin 
49543fe7d45SAlexander Motin 	ET_LOCK();
49643fe7d45SAlexander Motin 	et = timer[1];
49743fe7d45SAlexander Motin 	if (et == NULL)
49843fe7d45SAlexander Motin 		snprintf(buf, sizeof(buf), "NONE");
49943fe7d45SAlexander Motin 	else
50043fe7d45SAlexander Motin 		snprintf(buf, sizeof(buf), "%s", et->et_name);
50143fe7d45SAlexander Motin 	ET_UNLOCK();
50243fe7d45SAlexander Motin 	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
50343fe7d45SAlexander Motin 	ET_LOCK();
50443fe7d45SAlexander Motin 	et = timer[1];
50543fe7d45SAlexander Motin 	if (error != 0 || req->newptr == NULL ||
50643fe7d45SAlexander Motin 	    strcmp(buf, et ? et->et_name : "NONE") == 0) {
50743fe7d45SAlexander Motin 		ET_UNLOCK();
50843fe7d45SAlexander Motin 		return (error);
50943fe7d45SAlexander Motin 	}
51043fe7d45SAlexander Motin 	et = et_find(buf, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
51143fe7d45SAlexander Motin 	if (et == NULL && strcasecmp(buf, "NONE") != 0) {
51243fe7d45SAlexander Motin 		ET_UNLOCK();
51343fe7d45SAlexander Motin 		return (ENOENT);
51443fe7d45SAlexander Motin 	}
51543fe7d45SAlexander Motin 	if (timer[1] != NULL) {
51643fe7d45SAlexander Motin 		timer2hz = 0;
51743fe7d45SAlexander Motin 		configtimer(1);
51843fe7d45SAlexander Motin 		et_free(timer[1]);
51943fe7d45SAlexander Motin 	}
52043fe7d45SAlexander Motin 	timer[1] = et;
52143fe7d45SAlexander Motin 	if (timer[1] != NULL)
52243fe7d45SAlexander Motin 		et_init(timer[1], timer2cb, NULL, NULL);
52343fe7d45SAlexander Motin 	cpu_restartclocks();
52443fe7d45SAlexander Motin 	ET_UNLOCK();
52543fe7d45SAlexander Motin 	return (error);
52643fe7d45SAlexander Motin }
52743fe7d45SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer2,
52843fe7d45SAlexander Motin     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
52943fe7d45SAlexander Motin     0, 0, sysctl_kern_eventtimer_timer2, "A", "Secondary event timer");
53043fe7d45SAlexander Motin 
53143fe7d45SAlexander Motin #endif
53243fe7d45SAlexander Motin 
533