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