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