143fe7d45SAlexander Motin /*- 2*5b999a6bSDavide Italiano * Copyright (c) 2010-2013 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 349dfc483cSAlexander Motin #include "opt_device_polling.h" 3543fe7d45SAlexander Motin #include "opt_kdtrace.h" 3643fe7d45SAlexander Motin 3743fe7d45SAlexander Motin #include <sys/param.h> 3843fe7d45SAlexander Motin #include <sys/systm.h> 3943fe7d45SAlexander Motin #include <sys/bus.h> 40*5b999a6bSDavide Italiano #include <sys/limits.h> 4143fe7d45SAlexander Motin #include <sys/lock.h> 4243fe7d45SAlexander Motin #include <sys/kdb.h> 43a157e425SAlexander Motin #include <sys/ktr.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> 510e189873SAlexander Motin #include <sys/timetc.h> 5243fe7d45SAlexander Motin 5343fe7d45SAlexander Motin #include <machine/atomic.h> 5443fe7d45SAlexander Motin #include <machine/clock.h> 5543fe7d45SAlexander Motin #include <machine/cpu.h> 5643fe7d45SAlexander Motin #include <machine/smp.h> 5743fe7d45SAlexander Motin 5843fe7d45SAlexander Motin #ifdef KDTRACE_HOOKS 5943fe7d45SAlexander Motin #include <sys/dtrace_bsd.h> 60dd7498aeSAndriy Gapon cyclic_clock_func_t cyclic_clock_func = NULL; 6143fe7d45SAlexander Motin #endif 6243fe7d45SAlexander Motin 63a49399a9SJung-uk Kim int cpu_can_deep_sleep = 0; /* C3 state is available. */ 64a157e425SAlexander Motin int cpu_disable_deep_sleep = 0; /* Timer dies in C3. */ 6543fe7d45SAlexander Motin 66a157e425SAlexander Motin static void setuptimer(void); 67*5b999a6bSDavide Italiano static void loadtimer(sbintime_t now, int first); 68a157e425SAlexander Motin static int doconfigtimer(void); 69a157e425SAlexander Motin static void configtimer(int start); 70a157e425SAlexander Motin static int round_freq(struct eventtimer *et, int freq); 7143fe7d45SAlexander Motin 72*5b999a6bSDavide Italiano static sbintime_t getnextcpuevent(int idle); 73*5b999a6bSDavide Italiano static sbintime_t getnextevent(void); 74*5b999a6bSDavide Italiano static int handleevents(sbintime_t now, int fake); 7543fe7d45SAlexander Motin 76a157e425SAlexander Motin static struct mtx et_hw_mtx; 77a157e425SAlexander Motin 78a157e425SAlexander Motin #define ET_HW_LOCK(state) \ 79a157e425SAlexander Motin { \ 80a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 81a157e425SAlexander Motin mtx_lock_spin(&(state)->et_hw_mtx); \ 82a157e425SAlexander Motin else \ 83a157e425SAlexander Motin mtx_lock_spin(&et_hw_mtx); \ 84a157e425SAlexander Motin } 85a157e425SAlexander Motin 86a157e425SAlexander Motin #define ET_HW_UNLOCK(state) \ 87a157e425SAlexander Motin { \ 88a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 89a157e425SAlexander Motin mtx_unlock_spin(&(state)->et_hw_mtx); \ 90a157e425SAlexander Motin else \ 91a157e425SAlexander Motin mtx_unlock_spin(&et_hw_mtx); \ 92a157e425SAlexander Motin } 93a157e425SAlexander Motin 94a157e425SAlexander Motin static struct eventtimer *timer = NULL; 95*5b999a6bSDavide Italiano static sbintime_t timerperiod; /* Timer period for periodic mode. */ 96*5b999a6bSDavide Italiano static sbintime_t statperiod; /* statclock() events period. */ 97*5b999a6bSDavide Italiano static sbintime_t profperiod; /* profclock() events period. */ 98*5b999a6bSDavide Italiano static sbintime_t nexttick; /* Next global timer tick time. */ 99*5b999a6bSDavide Italiano static u_int busy = 1; /* Reconfiguration is in progress. */ 100a157e425SAlexander Motin static int profiling = 0; /* Profiling events enabled. */ 101a157e425SAlexander Motin 102a157e425SAlexander Motin static char timername[32]; /* Wanted timer. */ 103a157e425SAlexander Motin TUNABLE_STR("kern.eventtimer.timer", timername, sizeof(timername)); 104a157e425SAlexander Motin 105dd9595e7SAlexander Motin static int singlemul = 0; /* Multiplier for periodic mode. */ 10643fe7d45SAlexander Motin TUNABLE_INT("kern.eventtimer.singlemul", &singlemul); 10743fe7d45SAlexander Motin SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul, 108a157e425SAlexander Motin 0, "Multiplier for periodic mode"); 10943fe7d45SAlexander Motin 110fd053faeSAlexander Motin static u_int idletick = 0; /* Run periodic events when idle. */ 111a157e425SAlexander Motin TUNABLE_INT("kern.eventtimer.idletick", &idletick); 112fbbb13f9SMatthew D Fleming SYSCTL_UINT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RW, &idletick, 113a157e425SAlexander Motin 0, "Run periodic events when idle"); 114a157e425SAlexander Motin 115a157e425SAlexander Motin static int periodic = 0; /* Periodic or one-shot mode. */ 116afe41f2dSAlexander Motin static int want_periodic = 0; /* What mode to prefer. */ 117afe41f2dSAlexander Motin TUNABLE_INT("kern.eventtimer.periodic", &want_periodic); 118a157e425SAlexander Motin 119a157e425SAlexander Motin struct pcpu_state { 120a157e425SAlexander Motin struct mtx et_hw_mtx; /* Per-CPU timer mutex. */ 121a157e425SAlexander Motin u_int action; /* Reconfiguration requests. */ 122a157e425SAlexander Motin u_int handle; /* Immediate handle resuests. */ 123*5b999a6bSDavide Italiano sbintime_t now; /* Last tick time. */ 124*5b999a6bSDavide Italiano sbintime_t nextevent; /* Next scheduled event on this CPU. */ 125*5b999a6bSDavide Italiano sbintime_t nexttick; /* Next timer tick time. */ 126*5b999a6bSDavide Italiano sbintime_t nexthard; /* Next hardlock() event. */ 127*5b999a6bSDavide Italiano sbintime_t nextstat; /* Next statclock() event. */ 128*5b999a6bSDavide Italiano sbintime_t nextprof; /* Next profclock() event. */ 129*5b999a6bSDavide Italiano sbintime_t nextcall; /* Next callout event. */ 130*5b999a6bSDavide Italiano sbintime_t nextcallopt; /* Next optional callout event. */ 131dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 132*5b999a6bSDavide Italiano sbintime_t nextcyc; /* Next OpenSolaris cyclics event. */ 133dd7498aeSAndriy Gapon #endif 134a157e425SAlexander Motin int ipi; /* This CPU needs IPI. */ 135a157e425SAlexander Motin int idle; /* This CPU is in idle mode. */ 136a157e425SAlexander Motin }; 137a157e425SAlexander Motin 1383e288e62SDimitry Andric static DPCPU_DEFINE(struct pcpu_state, timerstate); 139*5b999a6bSDavide Italiano DPCPU_DEFINE(sbintime_t, hardclocktime); 140fdc5dd2dSAlexander Motin 141a157e425SAlexander Motin /* 142a157e425SAlexander Motin * Timer broadcast IPI handler. 143a157e425SAlexander Motin */ 144a157e425SAlexander Motin int 145a157e425SAlexander Motin hardclockintr(void) 14643fe7d45SAlexander Motin { 147*5b999a6bSDavide Italiano sbintime_t now; 148a157e425SAlexander Motin struct pcpu_state *state; 149a157e425SAlexander Motin int done; 15043fe7d45SAlexander Motin 151a157e425SAlexander Motin if (doconfigtimer() || busy) 152a157e425SAlexander Motin return (FILTER_HANDLED); 153a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 154a157e425SAlexander Motin now = state->now; 155*5b999a6bSDavide Italiano CTR3(KTR_SPARE2, "ipi at %d: now %d.%08x", 156*5b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 157*5b999a6bSDavide Italiano done = handleevents(now, 0); 158a157e425SAlexander Motin return (done ? FILTER_HANDLED : FILTER_STRAY); 159a157e425SAlexander Motin } 160a157e425SAlexander Motin 161a157e425SAlexander Motin /* 162a157e425SAlexander Motin * Handle all events for specified time on this CPU 163a157e425SAlexander Motin */ 164a157e425SAlexander Motin static int 165*5b999a6bSDavide Italiano handleevents(sbintime_t now, int fake) 166a157e425SAlexander Motin { 167*5b999a6bSDavide Italiano sbintime_t t, *hct; 168a157e425SAlexander Motin struct trapframe *frame; 169a157e425SAlexander Motin struct pcpu_state *state; 170a157e425SAlexander Motin int usermode; 171a157e425SAlexander Motin int done, runs; 172a157e425SAlexander Motin 173*5b999a6bSDavide Italiano CTR3(KTR_SPARE2, "handle at %d: now %d.%08x", 174*5b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 175a157e425SAlexander Motin done = 0; 176a157e425SAlexander Motin if (fake) { 177a157e425SAlexander Motin frame = NULL; 178a157e425SAlexander Motin usermode = 0; 179a157e425SAlexander Motin } else { 180a157e425SAlexander Motin frame = curthread->td_intr_frame; 181a157e425SAlexander Motin usermode = TRAPF_USERMODE(frame); 182a157e425SAlexander Motin } 183dd7498aeSAndriy Gapon 184a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 185dd7498aeSAndriy Gapon 186bcfd016cSAlexander Motin runs = 0; 187*5b999a6bSDavide Italiano while (now >= state->nexthard) { 188*5b999a6bSDavide Italiano state->nexthard += tick_sbt; 189a157e425SAlexander Motin runs++; 19043fe7d45SAlexander Motin } 191c0722d20SAlexander Motin if (runs) { 192*5b999a6bSDavide Italiano hct = DPCPU_PTR(hardclocktime); 193*5b999a6bSDavide Italiano *hct = state->nexthard - tick_sbt; 194c0722d20SAlexander Motin if (fake < 2) { 195bcfd016cSAlexander Motin hardclock_cnt(runs, usermode); 196a157e425SAlexander Motin done = 1; 19743fe7d45SAlexander Motin } 198c0722d20SAlexander Motin } 199bcfd016cSAlexander Motin runs = 0; 200*5b999a6bSDavide Italiano while (now >= state->nextstat) { 201*5b999a6bSDavide Italiano state->nextstat += statperiod; 202bcfd016cSAlexander Motin runs++; 203bcfd016cSAlexander Motin } 204bcfd016cSAlexander Motin if (runs && fake < 2) { 205bcfd016cSAlexander Motin statclock_cnt(runs, usermode); 206a157e425SAlexander Motin done = 1; 20743fe7d45SAlexander Motin } 208a157e425SAlexander Motin if (profiling) { 209bcfd016cSAlexander Motin runs = 0; 210*5b999a6bSDavide Italiano while (now >= state->nextprof) { 211*5b999a6bSDavide Italiano state->nextprof += profperiod; 212bcfd016cSAlexander Motin runs++; 213bcfd016cSAlexander Motin } 214bcfd016cSAlexander Motin if (runs && !fake) { 215*5b999a6bSDavide Italiano profclock_cnt(runs, usermode, TRAPF_PC(frame)); 216a157e425SAlexander Motin done = 1; 21743fe7d45SAlexander Motin } 218a157e425SAlexander Motin } else 219a157e425SAlexander Motin state->nextprof = state->nextstat; 220*5b999a6bSDavide Italiano if (now >= state->nextcallopt) { 221*5b999a6bSDavide Italiano state->nextcall = state->nextcallopt = INT64_MAX; 222*5b999a6bSDavide Italiano callout_process(now); 223*5b999a6bSDavide Italiano } 224dd7498aeSAndriy Gapon 225dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 226*5b999a6bSDavide Italiano if (fake == 0 && now >= state->nextcyc && cyclic_clock_func != NULL) { 227*5b999a6bSDavide Italiano state->nextcyc = INT64_MAX; 228dd7498aeSAndriy Gapon (*cyclic_clock_func)(frame); 229dd7498aeSAndriy Gapon } 230dd7498aeSAndriy Gapon #endif 231dd7498aeSAndriy Gapon 232*5b999a6bSDavide Italiano t = getnextcpuevent(0); 233a157e425SAlexander Motin ET_HW_LOCK(state); 234a157e425SAlexander Motin if (!busy) { 235a157e425SAlexander Motin state->idle = 0; 236a157e425SAlexander Motin state->nextevent = t; 237a157e425SAlexander Motin loadtimer(now, 0); 23843fe7d45SAlexander Motin } 239a157e425SAlexander Motin ET_HW_UNLOCK(state); 240a157e425SAlexander Motin return (done); 24143fe7d45SAlexander Motin } 24243fe7d45SAlexander Motin 24343fe7d45SAlexander Motin /* 244a157e425SAlexander Motin * Schedule binuptime of the next event on current CPU. 24543fe7d45SAlexander Motin */ 246*5b999a6bSDavide Italiano static sbintime_t 247*5b999a6bSDavide Italiano getnextcpuevent(int idle) 24843fe7d45SAlexander Motin { 249*5b999a6bSDavide Italiano sbintime_t event; 250a157e425SAlexander Motin struct pcpu_state *state; 251*5b999a6bSDavide Italiano u_int hardfreq; 25243fe7d45SAlexander Motin 253a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 254*5b999a6bSDavide Italiano /* Handle hardclock() events, skipping some if CPU is idle. */ 255*5b999a6bSDavide Italiano event = state->nexthard; 256*5b999a6bSDavide Italiano if (idle) { 257*5b999a6bSDavide Italiano hardfreq = (u_int)hz / 2; 258*5b999a6bSDavide Italiano if (tc_min_ticktock_freq > 2 259*5b999a6bSDavide Italiano #ifdef SMP 260*5b999a6bSDavide Italiano && curcpu == CPU_FIRST() 261*5b999a6bSDavide Italiano #endif 262*5b999a6bSDavide Italiano ) 263*5b999a6bSDavide Italiano hardfreq = hz / tc_min_ticktock_freq; 264*5b999a6bSDavide Italiano if (hardfreq > 1) 265*5b999a6bSDavide Italiano event += tick_sbt * (hardfreq - 1); 266fd053faeSAlexander Motin } 267*5b999a6bSDavide Italiano /* Handle callout events. */ 268*5b999a6bSDavide Italiano if (event > state->nextcall) 269*5b999a6bSDavide Italiano event = state->nextcall; 270fd053faeSAlexander Motin if (!idle) { /* If CPU is active - handle other types of events. */ 271*5b999a6bSDavide Italiano if (event > state->nextstat) 272*5b999a6bSDavide Italiano event = state->nextstat; 273*5b999a6bSDavide Italiano if (profiling && event > state->nextprof) 274*5b999a6bSDavide Italiano event = state->nextprof; 27543fe7d45SAlexander Motin } 276dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 277*5b999a6bSDavide Italiano if (event > state->nextcyc) 278*5b999a6bSDavide Italiano event = state->nextcyc; 279dd7498aeSAndriy Gapon #endif 280*5b999a6bSDavide Italiano return (event); 28143fe7d45SAlexander Motin } 282a157e425SAlexander Motin 283a157e425SAlexander Motin /* 284a157e425SAlexander Motin * Schedule binuptime of the next event on all CPUs. 285a157e425SAlexander Motin */ 286*5b999a6bSDavide Italiano static sbintime_t 287*5b999a6bSDavide Italiano getnextevent(void) 288a157e425SAlexander Motin { 289a157e425SAlexander Motin struct pcpu_state *state; 290*5b999a6bSDavide Italiano sbintime_t event; 291a157e425SAlexander Motin #ifdef SMP 292a157e425SAlexander Motin int cpu; 293a157e425SAlexander Motin #endif 294*5b999a6bSDavide Italiano int c; 295a157e425SAlexander Motin 296a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 297*5b999a6bSDavide Italiano event = state->nextevent; 298*5b999a6bSDavide Italiano c = -1; 299fd053faeSAlexander Motin #ifdef SMP 300*5b999a6bSDavide Italiano if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) { 301a157e425SAlexander Motin CPU_FOREACH(cpu) { 302a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 303*5b999a6bSDavide Italiano if (event > state->nextevent) { 304*5b999a6bSDavide Italiano event = state->nextevent; 305a157e425SAlexander Motin c = cpu; 30643fe7d45SAlexander Motin } 30743fe7d45SAlexander Motin } 3082d7d1642SGrzegorz Bernacki } 309a157e425SAlexander Motin #endif 310*5b999a6bSDavide Italiano CTR4(KTR_SPARE2, "next at %d: next %d.%08x by %d", 311*5b999a6bSDavide Italiano curcpu, (int)(event >> 32), (u_int)(event & 0xffffffff), c); 312*5b999a6bSDavide Italiano return (event); 313a157e425SAlexander Motin } 314a157e425SAlexander Motin 315a157e425SAlexander Motin /* Hardware timer callback function. */ 316a157e425SAlexander Motin static void 317a157e425SAlexander Motin timercb(struct eventtimer *et, void *arg) 318a157e425SAlexander Motin { 319*5b999a6bSDavide Italiano sbintime_t now; 320*5b999a6bSDavide Italiano sbintime_t *next; 321a157e425SAlexander Motin struct pcpu_state *state; 322a157e425SAlexander Motin #ifdef SMP 323a157e425SAlexander Motin int cpu, bcast; 324a157e425SAlexander Motin #endif 325a157e425SAlexander Motin 326a157e425SAlexander Motin /* Do not touch anything if somebody reconfiguring timers. */ 327a157e425SAlexander Motin if (busy) 328a157e425SAlexander Motin return; 329a157e425SAlexander Motin /* Update present and next tick times. */ 330a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 331a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_PERCPU) { 332a157e425SAlexander Motin next = &state->nexttick; 333a157e425SAlexander Motin } else 334a157e425SAlexander Motin next = &nexttick; 335*5b999a6bSDavide Italiano now = sbinuptime(); 336*5b999a6bSDavide Italiano if (periodic) 337*5b999a6bSDavide Italiano *next = now + timerperiod; 338*5b999a6bSDavide Italiano else 339*5b999a6bSDavide Italiano *next = -1; /* Next tick is not scheduled yet. */ 340a157e425SAlexander Motin state->now = now; 341*5b999a6bSDavide Italiano CTR3(KTR_SPARE2, "intr at %d: now %d.%08x", 342*5b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 343a157e425SAlexander Motin 344a157e425SAlexander Motin #ifdef SMP 345a157e425SAlexander Motin /* Prepare broadcasting to other CPUs for non-per-CPU timers. */ 346a157e425SAlexander Motin bcast = 0; 347a157e425SAlexander Motin if ((et->et_flags & ET_FLAGS_PERCPU) == 0 && smp_started) { 348a157e425SAlexander Motin CPU_FOREACH(cpu) { 349a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 350a157e425SAlexander Motin ET_HW_LOCK(state); 351a157e425SAlexander Motin state->now = now; 352*5b999a6bSDavide Italiano if (now >= state->nextevent) { 353*5b999a6bSDavide Italiano state->nextevent += SBT_1S; 3548e860de4SAlexander Motin if (curcpu != cpu) { 355a157e425SAlexander Motin state->ipi = 1; 356a157e425SAlexander Motin bcast = 1; 357a157e425SAlexander Motin } 3588e860de4SAlexander Motin } 359a157e425SAlexander Motin ET_HW_UNLOCK(state); 360a157e425SAlexander Motin } 361a157e425SAlexander Motin } 362a157e425SAlexander Motin #endif 363a157e425SAlexander Motin 364a157e425SAlexander Motin /* Handle events for this time on this CPU. */ 365*5b999a6bSDavide Italiano handleevents(now, 0); 366a157e425SAlexander Motin 367a157e425SAlexander Motin #ifdef SMP 368a157e425SAlexander Motin /* Broadcast interrupt to other CPUs for non-per-CPU timers. */ 369a157e425SAlexander Motin if (bcast) { 370a157e425SAlexander Motin CPU_FOREACH(cpu) { 371a157e425SAlexander Motin if (curcpu == cpu) 372a157e425SAlexander Motin continue; 373a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 374a157e425SAlexander Motin if (state->ipi) { 375a157e425SAlexander Motin state->ipi = 0; 376a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 377a157e425SAlexander Motin } 378a157e425SAlexander Motin } 379a157e425SAlexander Motin } 380a157e425SAlexander Motin #endif 381a157e425SAlexander Motin } 382a157e425SAlexander Motin 383a157e425SAlexander Motin /* 384a157e425SAlexander Motin * Load new value into hardware timer. 385a157e425SAlexander Motin */ 386a157e425SAlexander Motin static void 387*5b999a6bSDavide Italiano loadtimer(sbintime_t now, int start) 388a157e425SAlexander Motin { 389a157e425SAlexander Motin struct pcpu_state *state; 390*5b999a6bSDavide Italiano sbintime_t new; 391*5b999a6bSDavide Italiano sbintime_t *next; 392a157e425SAlexander Motin uint64_t tmp; 393a157e425SAlexander Motin int eq; 394a157e425SAlexander Motin 395c70410e6SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) { 396c70410e6SAlexander Motin state = DPCPU_PTR(timerstate); 397c70410e6SAlexander Motin next = &state->nexttick; 398c70410e6SAlexander Motin } else 399c70410e6SAlexander Motin next = &nexttick; 400a157e425SAlexander Motin if (periodic) { 401a157e425SAlexander Motin if (start) { 402a157e425SAlexander Motin /* 403a157e425SAlexander Motin * Try to start all periodic timers aligned 404a157e425SAlexander Motin * to period to make events synchronous. 405a157e425SAlexander Motin */ 406*5b999a6bSDavide Italiano tmp = now % timerperiod; 407*5b999a6bSDavide Italiano new = timerperiod - tmp; 408*5b999a6bSDavide Italiano if (new < tmp) /* Left less then passed. */ 409*5b999a6bSDavide Italiano new += timerperiod; 410a157e425SAlexander Motin CTR5(KTR_SPARE2, "load p at %d: now %d.%08x first in %d.%08x", 411*5b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff), 412*5b999a6bSDavide Italiano (int)(new >> 32), (u_int)(new & 0xffffffff)); 413*5b999a6bSDavide Italiano *next = new + now; 414*5b999a6bSDavide Italiano et_start(timer, new, timerperiod); 415a157e425SAlexander Motin } 416a157e425SAlexander Motin } else { 417*5b999a6bSDavide Italiano new = getnextevent(); 418*5b999a6bSDavide Italiano eq = (new == *next); 419*5b999a6bSDavide Italiano CTR4(KTR_SPARE2, "load at %d: next %d.%08x eq %d", 420*5b999a6bSDavide Italiano curcpu, (int)(new >> 32), (u_int)(new & 0xffffffff), eq); 421a157e425SAlexander Motin if (!eq) { 422a157e425SAlexander Motin *next = new; 423*5b999a6bSDavide Italiano et_start(timer, new - now, 0); 424a157e425SAlexander Motin } 425a157e425SAlexander Motin } 426a157e425SAlexander Motin } 427a157e425SAlexander Motin 428a157e425SAlexander Motin /* 429a157e425SAlexander Motin * Prepare event timer parameters after configuration changes. 430a157e425SAlexander Motin */ 431a157e425SAlexander Motin static void 432a157e425SAlexander Motin setuptimer(void) 433a157e425SAlexander Motin { 434a157e425SAlexander Motin int freq; 435a157e425SAlexander Motin 436a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 437a157e425SAlexander Motin periodic = 0; 438a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 439a157e425SAlexander Motin periodic = 1; 440dd9595e7SAlexander Motin singlemul = MIN(MAX(singlemul, 1), 20); 441a157e425SAlexander Motin freq = hz * singlemul; 442a157e425SAlexander Motin while (freq < (profiling ? profhz : stathz)) 443a157e425SAlexander Motin freq += hz; 444a157e425SAlexander Motin freq = round_freq(timer, freq); 445*5b999a6bSDavide Italiano timerperiod = SBT_1S / freq; 446a157e425SAlexander Motin } 44743fe7d45SAlexander Motin 44843fe7d45SAlexander Motin /* 44943fe7d45SAlexander Motin * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler. 45043fe7d45SAlexander Motin */ 451a157e425SAlexander Motin static int 452a157e425SAlexander Motin doconfigtimer(void) 45343fe7d45SAlexander Motin { 454*5b999a6bSDavide Italiano sbintime_t now; 455a157e425SAlexander Motin struct pcpu_state *state; 45643fe7d45SAlexander Motin 457a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 458a157e425SAlexander Motin switch (atomic_load_acq_int(&state->action)) { 459a157e425SAlexander Motin case 1: 460*5b999a6bSDavide Italiano now = sbinuptime(); 461a157e425SAlexander Motin ET_HW_LOCK(state); 462*5b999a6bSDavide Italiano loadtimer(now, 1); 463a157e425SAlexander Motin ET_HW_UNLOCK(state); 464a157e425SAlexander Motin state->handle = 0; 465a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 466a157e425SAlexander Motin return (1); 467a157e425SAlexander Motin case 2: 468a157e425SAlexander Motin ET_HW_LOCK(state); 469a157e425SAlexander Motin et_stop(timer); 470a157e425SAlexander Motin ET_HW_UNLOCK(state); 471a157e425SAlexander Motin state->handle = 0; 472a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 473a157e425SAlexander Motin return (1); 474a157e425SAlexander Motin } 475a157e425SAlexander Motin if (atomic_readandclear_int(&state->handle) && !busy) { 476*5b999a6bSDavide Italiano now = sbinuptime(); 477*5b999a6bSDavide Italiano handleevents(now, 0); 47843fe7d45SAlexander Motin return (1); 47943fe7d45SAlexander Motin } 48043fe7d45SAlexander Motin return (0); 48143fe7d45SAlexander Motin } 48243fe7d45SAlexander Motin 48343fe7d45SAlexander Motin /* 48443fe7d45SAlexander Motin * Reconfigure specified timer. 48543fe7d45SAlexander Motin * For per-CPU timers use IPI to make other CPUs to reconfigure. 48643fe7d45SAlexander Motin */ 48743fe7d45SAlexander Motin static void 488a157e425SAlexander Motin configtimer(int start) 48943fe7d45SAlexander Motin { 490*5b999a6bSDavide Italiano sbintime_t now, next; 491a157e425SAlexander Motin struct pcpu_state *state; 49243fe7d45SAlexander Motin int cpu; 49343fe7d45SAlexander Motin 494a157e425SAlexander Motin if (start) { 495a157e425SAlexander Motin setuptimer(); 496*5b999a6bSDavide Italiano now = sbinuptime(); 497*5b999a6bSDavide Italiano } else 498*5b999a6bSDavide Italiano now = 0; 49943fe7d45SAlexander Motin critical_enter(); 500a157e425SAlexander Motin ET_HW_LOCK(DPCPU_PTR(timerstate)); 501a157e425SAlexander Motin if (start) { 502a157e425SAlexander Motin /* Initialize time machine parameters. */ 503*5b999a6bSDavide Italiano next = now + timerperiod; 504a157e425SAlexander Motin if (periodic) 505a157e425SAlexander Motin nexttick = next; 50643fe7d45SAlexander Motin else 507*5b999a6bSDavide Italiano nexttick = -1; 508a157e425SAlexander Motin CPU_FOREACH(cpu) { 509a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 510a157e425SAlexander Motin state->now = now; 511*5b999a6bSDavide Italiano if (!smp_started && cpu != CPU_FIRST()) 512*5b999a6bSDavide Italiano state->nextevent = INT64_MAX; 513*5b999a6bSDavide Italiano else 514a157e425SAlexander Motin state->nextevent = next; 515a157e425SAlexander Motin if (periodic) 516a157e425SAlexander Motin state->nexttick = next; 517a157e425SAlexander Motin else 518*5b999a6bSDavide Italiano state->nexttick = -1; 519a157e425SAlexander Motin state->nexthard = next; 520a157e425SAlexander Motin state->nextstat = next; 521a157e425SAlexander Motin state->nextprof = next; 522*5b999a6bSDavide Italiano state->nextcall = next; 523*5b999a6bSDavide Italiano state->nextcallopt = next; 524a157e425SAlexander Motin hardclock_sync(cpu); 525a157e425SAlexander Motin } 526a157e425SAlexander Motin busy = 0; 527a157e425SAlexander Motin /* Start global timer or per-CPU timer of this CPU. */ 528*5b999a6bSDavide Italiano loadtimer(now, 1); 529a157e425SAlexander Motin } else { 530a157e425SAlexander Motin busy = 1; 531a157e425SAlexander Motin /* Stop global timer or per-CPU timer of this CPU. */ 532a157e425SAlexander Motin et_stop(timer); 533a157e425SAlexander Motin } 534a157e425SAlexander Motin ET_HW_UNLOCK(DPCPU_PTR(timerstate)); 53543fe7d45SAlexander Motin #ifdef SMP 536a157e425SAlexander Motin /* If timer is global or there is no other CPUs yet - we are done. */ 537a157e425SAlexander Motin if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) { 53843fe7d45SAlexander Motin critical_exit(); 53943fe7d45SAlexander Motin return; 54043fe7d45SAlexander Motin } 54143fe7d45SAlexander Motin /* Set reconfigure flags for other CPUs. */ 54243fe7d45SAlexander Motin CPU_FOREACH(cpu) { 543a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 544a157e425SAlexander Motin atomic_store_rel_int(&state->action, 545a157e425SAlexander Motin (cpu == curcpu) ? 0 : ( start ? 1 : 2)); 54643fe7d45SAlexander Motin } 547a157e425SAlexander Motin /* Broadcast reconfigure IPI. */ 548a157e425SAlexander Motin ipi_all_but_self(IPI_HARDCLOCK); 54943fe7d45SAlexander Motin /* Wait for reconfiguration completed. */ 55043fe7d45SAlexander Motin restart: 55143fe7d45SAlexander Motin cpu_spinwait(); 55243fe7d45SAlexander Motin CPU_FOREACH(cpu) { 55343fe7d45SAlexander Motin if (cpu == curcpu) 55443fe7d45SAlexander Motin continue; 555a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 556a157e425SAlexander Motin if (atomic_load_acq_int(&state->action)) 55743fe7d45SAlexander Motin goto restart; 55843fe7d45SAlexander Motin } 55943fe7d45SAlexander Motin #endif 560a157e425SAlexander Motin critical_exit(); 56143fe7d45SAlexander Motin } 56243fe7d45SAlexander Motin 563a157e425SAlexander Motin /* 564a157e425SAlexander Motin * Calculate nearest frequency supported by hardware timer. 565a157e425SAlexander Motin */ 56651636352SAlexander Motin static int 56751636352SAlexander Motin round_freq(struct eventtimer *et, int freq) 56851636352SAlexander Motin { 56951636352SAlexander Motin uint64_t div; 57051636352SAlexander Motin 57151636352SAlexander Motin if (et->et_frequency != 0) { 572599cf0f1SAlexander Motin div = lmax((et->et_frequency + freq / 2) / freq, 1); 57351636352SAlexander Motin if (et->et_flags & ET_FLAGS_POW2DIV) 57451636352SAlexander Motin div = 1 << (flsl(div + div / 2) - 1); 57551636352SAlexander Motin freq = (et->et_frequency + div / 2) / div; 57651636352SAlexander Motin } 577fdc5dd2dSAlexander Motin if (et->et_min_period > SBT_1S) 578803a9b3eSAlexander Motin panic("Event timer \"%s\" doesn't support sub-second periods!", 579803a9b3eSAlexander Motin et->et_name); 580fdc5dd2dSAlexander Motin else if (et->et_min_period != 0) 581fdc5dd2dSAlexander Motin freq = min(freq, SBT2FREQ(et->et_min_period)); 582fdc5dd2dSAlexander Motin if (et->et_max_period < SBT_1S && et->et_max_period != 0) 583fdc5dd2dSAlexander Motin freq = max(freq, SBT2FREQ(et->et_max_period)); 58451636352SAlexander Motin return (freq); 58551636352SAlexander Motin } 58651636352SAlexander Motin 58743fe7d45SAlexander Motin /* 588a157e425SAlexander Motin * Configure and start event timers (BSP part). 58943fe7d45SAlexander Motin */ 59043fe7d45SAlexander Motin void 59143fe7d45SAlexander Motin cpu_initclocks_bsp(void) 59243fe7d45SAlexander Motin { 593a157e425SAlexander Motin struct pcpu_state *state; 594a157e425SAlexander Motin int base, div, cpu; 59543fe7d45SAlexander Motin 596a157e425SAlexander Motin mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 597a157e425SAlexander Motin CPU_FOREACH(cpu) { 598a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 599a157e425SAlexander Motin mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 600dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 601*5b999a6bSDavide Italiano state->nextcyc = INT64_MAX; 602dd7498aeSAndriy Gapon #endif 603*5b999a6bSDavide Italiano state->nextcall = INT64_MAX; 604*5b999a6bSDavide Italiano state->nextcallopt = INT64_MAX; 605a157e425SAlexander Motin } 606afe41f2dSAlexander Motin periodic = want_periodic; 607a157e425SAlexander Motin /* Grab requested timer or the best of present. */ 608a157e425SAlexander Motin if (timername[0]) 609a157e425SAlexander Motin timer = et_find(timername, 0, 0); 610a157e425SAlexander Motin if (timer == NULL && periodic) { 611a157e425SAlexander Motin timer = et_find(NULL, 61243fe7d45SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 613a157e425SAlexander Motin } 614a157e425SAlexander Motin if (timer == NULL) { 615a157e425SAlexander Motin timer = et_find(NULL, 616a157e425SAlexander Motin ET_FLAGS_ONESHOT, ET_FLAGS_ONESHOT); 617a157e425SAlexander Motin } 618a157e425SAlexander Motin if (timer == NULL && !periodic) { 619a157e425SAlexander Motin timer = et_find(NULL, 620a157e425SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 621a157e425SAlexander Motin } 622a157e425SAlexander Motin if (timer == NULL) 623a157e425SAlexander Motin panic("No usable event timer found!"); 624a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 625a157e425SAlexander Motin 626a157e425SAlexander Motin /* Adapt to timer capabilities. */ 627a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 628a157e425SAlexander Motin periodic = 0; 629a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 630a157e425SAlexander Motin periodic = 1; 631a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 632a157e425SAlexander Motin cpu_disable_deep_sleep++; 633a157e425SAlexander Motin 63443fe7d45SAlexander Motin /* 63543fe7d45SAlexander Motin * We honor the requested 'hz' value. 63643fe7d45SAlexander Motin * We want to run stathz in the neighborhood of 128hz. 63743fe7d45SAlexander Motin * We would like profhz to run as often as possible. 63843fe7d45SAlexander Motin */ 639dd9595e7SAlexander Motin if (singlemul <= 0 || singlemul > 20) { 64043fe7d45SAlexander Motin if (hz >= 1500 || (hz % 128) == 0) 64143fe7d45SAlexander Motin singlemul = 1; 64243fe7d45SAlexander Motin else if (hz >= 750) 64343fe7d45SAlexander Motin singlemul = 2; 64443fe7d45SAlexander Motin else 64543fe7d45SAlexander Motin singlemul = 4; 64643fe7d45SAlexander Motin } 647a157e425SAlexander Motin if (periodic) { 648a157e425SAlexander Motin base = round_freq(timer, hz * singlemul); 64951636352SAlexander Motin singlemul = max((base + hz / 2) / hz, 1); 65051636352SAlexander Motin hz = (base + singlemul / 2) / singlemul; 65151636352SAlexander Motin if (base <= 128) 65243fe7d45SAlexander Motin stathz = base; 65343fe7d45SAlexander Motin else { 65443fe7d45SAlexander Motin div = base / 128; 65551636352SAlexander Motin if (div >= singlemul && (div % singlemul) == 0) 65643fe7d45SAlexander Motin div++; 65743fe7d45SAlexander Motin stathz = base / div; 65843fe7d45SAlexander Motin } 65943fe7d45SAlexander Motin profhz = stathz; 66051636352SAlexander Motin while ((profhz + stathz) <= 128 * 64) 66143fe7d45SAlexander Motin profhz += stathz; 662a157e425SAlexander Motin profhz = round_freq(timer, profhz); 66343fe7d45SAlexander Motin } else { 664a157e425SAlexander Motin hz = round_freq(timer, hz); 665a157e425SAlexander Motin stathz = round_freq(timer, 127); 666a157e425SAlexander Motin profhz = round_freq(timer, stathz * 64); 66743fe7d45SAlexander Motin } 668599cf0f1SAlexander Motin tick = 1000000 / hz; 669*5b999a6bSDavide Italiano tick_sbt = SBT_1S / hz; 670*5b999a6bSDavide Italiano tick_bt = sbttobt(tick_sbt); 671*5b999a6bSDavide Italiano statperiod = SBT_1S / stathz; 672*5b999a6bSDavide Italiano profperiod = SBT_1S / profhz; 67343fe7d45SAlexander Motin ET_LOCK(); 674a157e425SAlexander Motin configtimer(1); 67543fe7d45SAlexander Motin ET_UNLOCK(); 67643fe7d45SAlexander Motin } 67743fe7d45SAlexander Motin 678a157e425SAlexander Motin /* 679a157e425SAlexander Motin * Start per-CPU event timers on APs. 680a157e425SAlexander Motin */ 68143fe7d45SAlexander Motin void 68243fe7d45SAlexander Motin cpu_initclocks_ap(void) 68343fe7d45SAlexander Motin { 684*5b999a6bSDavide Italiano sbintime_t now; 685a157e425SAlexander Motin struct pcpu_state *state; 686*5b999a6bSDavide Italiano struct thread *td; 68743fe7d45SAlexander Motin 688a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 689*5b999a6bSDavide Italiano now = sbinuptime(); 690a157e425SAlexander Motin ET_HW_LOCK(state); 691c70410e6SAlexander Motin state->now = now; 692c70410e6SAlexander Motin hardclock_sync(curcpu); 693*5b999a6bSDavide Italiano spinlock_enter(); 694a157e425SAlexander Motin ET_HW_UNLOCK(state); 695*5b999a6bSDavide Italiano td = curthread; 696*5b999a6bSDavide Italiano td->td_intr_nesting_level++; 697*5b999a6bSDavide Italiano handleevents(state->now, 2); 698*5b999a6bSDavide Italiano td->td_intr_nesting_level--; 699*5b999a6bSDavide Italiano spinlock_exit(); 70043fe7d45SAlexander Motin } 70143fe7d45SAlexander Motin 702a157e425SAlexander Motin /* 703a157e425SAlexander Motin * Switch to profiling clock rates. 704a157e425SAlexander Motin */ 70543fe7d45SAlexander Motin void 70643fe7d45SAlexander Motin cpu_startprofclock(void) 70743fe7d45SAlexander Motin { 70843fe7d45SAlexander Motin 70943fe7d45SAlexander Motin ET_LOCK(); 7101af19ee4SAlexander Motin if (profiling == 0) { 711a157e425SAlexander Motin if (periodic) { 712a157e425SAlexander Motin configtimer(0); 713a157e425SAlexander Motin profiling = 1; 714a157e425SAlexander Motin configtimer(1); 715a157e425SAlexander Motin } else 716a157e425SAlexander Motin profiling = 1; 7171af19ee4SAlexander Motin } else 7181af19ee4SAlexander Motin profiling++; 71943fe7d45SAlexander Motin ET_UNLOCK(); 72043fe7d45SAlexander Motin } 72143fe7d45SAlexander Motin 722a157e425SAlexander Motin /* 723a157e425SAlexander Motin * Switch to regular clock rates. 724a157e425SAlexander Motin */ 72543fe7d45SAlexander Motin void 72643fe7d45SAlexander Motin cpu_stopprofclock(void) 72743fe7d45SAlexander Motin { 72843fe7d45SAlexander Motin 72943fe7d45SAlexander Motin ET_LOCK(); 7301af19ee4SAlexander Motin if (profiling == 1) { 731a157e425SAlexander Motin if (periodic) { 732a157e425SAlexander Motin configtimer(0); 733a157e425SAlexander Motin profiling = 0; 734a157e425SAlexander Motin configtimer(1); 735a157e425SAlexander Motin } else 736a157e425SAlexander Motin profiling = 0; 7371af19ee4SAlexander Motin } else 7381af19ee4SAlexander Motin profiling--; 73943fe7d45SAlexander Motin ET_UNLOCK(); 74043fe7d45SAlexander Motin } 74143fe7d45SAlexander Motin 742a157e425SAlexander Motin /* 743a157e425SAlexander Motin * Switch to idle mode (all ticks handled). 744a157e425SAlexander Motin */ 745acccf7d8SDavide Italiano sbintime_t 746a157e425SAlexander Motin cpu_idleclock(void) 747a157e425SAlexander Motin { 748*5b999a6bSDavide Italiano sbintime_t now, t; 749a157e425SAlexander Motin struct pcpu_state *state; 750a157e425SAlexander Motin 751a157e425SAlexander Motin if (idletick || busy || 7529dfc483cSAlexander Motin (periodic && (timer->et_flags & ET_FLAGS_PERCPU)) 7539dfc483cSAlexander Motin #ifdef DEVICE_POLLING 7549dfc483cSAlexander Motin || curcpu == CPU_FIRST() 7559dfc483cSAlexander Motin #endif 7569dfc483cSAlexander Motin ) 757acccf7d8SDavide Italiano return (-1); 758a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 759a157e425SAlexander Motin if (periodic) 760a157e425SAlexander Motin now = state->now; 761a157e425SAlexander Motin else 762*5b999a6bSDavide Italiano now = sbinuptime(); 763*5b999a6bSDavide Italiano CTR3(KTR_SPARE2, "idle at %d: now %d.%08x", 764*5b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 765*5b999a6bSDavide Italiano t = getnextcpuevent(1); 766a157e425SAlexander Motin ET_HW_LOCK(state); 767a157e425SAlexander Motin state->idle = 1; 768a157e425SAlexander Motin state->nextevent = t; 769a157e425SAlexander Motin if (!periodic) 770*5b999a6bSDavide Italiano loadtimer(now, 0); 771a157e425SAlexander Motin ET_HW_UNLOCK(state); 772*5b999a6bSDavide Italiano return (MAX(t - now, 0)); 773a157e425SAlexander Motin } 774a157e425SAlexander Motin 775a157e425SAlexander Motin /* 776a157e425SAlexander Motin * Switch to active mode (skip empty ticks). 777a157e425SAlexander Motin */ 778a157e425SAlexander Motin void 779a157e425SAlexander Motin cpu_activeclock(void) 780a157e425SAlexander Motin { 781*5b999a6bSDavide Italiano sbintime_t now; 782a157e425SAlexander Motin struct pcpu_state *state; 783a157e425SAlexander Motin struct thread *td; 784a157e425SAlexander Motin 785a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 786a157e425SAlexander Motin if (state->idle == 0 || busy) 787a157e425SAlexander Motin return; 788a157e425SAlexander Motin if (periodic) 789a157e425SAlexander Motin now = state->now; 790a157e425SAlexander Motin else 791*5b999a6bSDavide Italiano now = sbinuptime(); 792*5b999a6bSDavide Italiano CTR3(KTR_SPARE2, "active at %d: now %d.%08x", 793*5b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 794a157e425SAlexander Motin spinlock_enter(); 795a157e425SAlexander Motin td = curthread; 796a157e425SAlexander Motin td->td_intr_nesting_level++; 797*5b999a6bSDavide Italiano handleevents(now, 1); 798a157e425SAlexander Motin td->td_intr_nesting_level--; 799a157e425SAlexander Motin spinlock_exit(); 800a157e425SAlexander Motin } 801a157e425SAlexander Motin 802dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 803dd7498aeSAndriy Gapon void 804*5b999a6bSDavide Italiano clocksource_cyc_set(const struct bintime *bt) 805dd7498aeSAndriy Gapon { 806*5b999a6bSDavide Italiano sbintime_t now, t; 807dd7498aeSAndriy Gapon struct pcpu_state *state; 808dd7498aeSAndriy Gapon 809*5b999a6bSDavide Italiano /* Do not touch anything if somebody reconfiguring timers. */ 810*5b999a6bSDavide Italiano if (busy) 811*5b999a6bSDavide Italiano return; 812*5b999a6bSDavide Italiano t = bttosbt(*bt); 813dd7498aeSAndriy Gapon state = DPCPU_PTR(timerstate); 814dd7498aeSAndriy Gapon if (periodic) 815dd7498aeSAndriy Gapon now = state->now; 816dd7498aeSAndriy Gapon else 817*5b999a6bSDavide Italiano now = sbinuptime(); 818dd7498aeSAndriy Gapon 819*5b999a6bSDavide Italiano CTR5(KTR_SPARE2, "set_cyc at %d: now %d.%08x t %d.%08x", 820*5b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff), 821*5b999a6bSDavide Italiano (int)(t >> 32), (u_int)(t & 0xffffffff)); 822dd7498aeSAndriy Gapon 823dd7498aeSAndriy Gapon ET_HW_LOCK(state); 824*5b999a6bSDavide Italiano if (t == state->nextcyc) 825*5b999a6bSDavide Italiano goto done; 826*5b999a6bSDavide Italiano state->nextcyc = t; 827*5b999a6bSDavide Italiano if (t >= state->nextevent) 828*5b999a6bSDavide Italiano goto done; 829*5b999a6bSDavide Italiano state->nextevent = t; 830dd7498aeSAndriy Gapon if (!periodic) 831*5b999a6bSDavide Italiano loadtimer(now, 0); 832*5b999a6bSDavide Italiano done: 833dd7498aeSAndriy Gapon ET_HW_UNLOCK(state); 834dd7498aeSAndriy Gapon } 835dd7498aeSAndriy Gapon #endif 836dd7498aeSAndriy Gapon 837*5b999a6bSDavide Italiano void 838*5b999a6bSDavide Italiano cpu_new_callout(int cpu, sbintime_t bt, sbintime_t bt_opt) 839a157e425SAlexander Motin { 840a157e425SAlexander Motin struct pcpu_state *state; 841a157e425SAlexander Motin 842*5b999a6bSDavide Italiano /* Do not touch anything if somebody reconfiguring timers. */ 843*5b999a6bSDavide Italiano if (busy) 844*5b999a6bSDavide Italiano return; 845*5b999a6bSDavide Italiano CTR6(KTR_SPARE2, "new co at %d: on %d at %d.%08x - %d.%08x", 846*5b999a6bSDavide Italiano curcpu, cpu, (int)(bt_opt >> 32), (u_int)(bt_opt & 0xffffffff), 847*5b999a6bSDavide Italiano (int)(bt >> 32), (u_int)(bt & 0xffffffff)); 848a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 849a157e425SAlexander Motin ET_HW_LOCK(state); 850*5b999a6bSDavide Italiano 851*5b999a6bSDavide Italiano /* 852*5b999a6bSDavide Italiano * If there is callout time already set earlier -- do nothing. 853*5b999a6bSDavide Italiano * This check may appear redundant because we check already in 854*5b999a6bSDavide Italiano * callout_process() but this double check guarantees we're safe 855*5b999a6bSDavide Italiano * with respect to race conditions between interrupts execution 856*5b999a6bSDavide Italiano * and scheduling. 857*5b999a6bSDavide Italiano */ 858*5b999a6bSDavide Italiano state->nextcallopt = bt_opt; 859*5b999a6bSDavide Italiano if (bt >= state->nextcall) 860*5b999a6bSDavide Italiano goto done; 861*5b999a6bSDavide Italiano state->nextcall = bt; 862*5b999a6bSDavide Italiano /* If there is some other event set earlier -- do nothing. */ 863*5b999a6bSDavide Italiano if (bt >= state->nextevent) 864*5b999a6bSDavide Italiano goto done; 865*5b999a6bSDavide Italiano state->nextevent = bt; 866*5b999a6bSDavide Italiano /* If timer is periodic -- there is nothing to reprogram. */ 867*5b999a6bSDavide Italiano if (periodic) 868*5b999a6bSDavide Italiano goto done; 869*5b999a6bSDavide Italiano /* If timer is global or of the current CPU -- reprogram it. */ 870*5b999a6bSDavide Italiano if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || cpu == curcpu) { 871*5b999a6bSDavide Italiano loadtimer(sbinuptime(), 0); 872*5b999a6bSDavide Italiano done: 873a157e425SAlexander Motin ET_HW_UNLOCK(state); 874a157e425SAlexander Motin return; 875a157e425SAlexander Motin } 876*5b999a6bSDavide Italiano /* Otherwise make other CPU to reprogram it. */ 877a157e425SAlexander Motin state->handle = 1; 878*5b999a6bSDavide Italiano ET_HW_UNLOCK(state); 879*5b999a6bSDavide Italiano #ifdef SMP 880a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 881a157e425SAlexander Motin #endif 882*5b999a6bSDavide Italiano } 883a157e425SAlexander Motin 884a157e425SAlexander Motin /* 885a157e425SAlexander Motin * Report or change the active event timers hardware. 886a157e425SAlexander Motin */ 88743fe7d45SAlexander Motin static int 888a157e425SAlexander Motin sysctl_kern_eventtimer_timer(SYSCTL_HANDLER_ARGS) 88943fe7d45SAlexander Motin { 89043fe7d45SAlexander Motin char buf[32]; 89143fe7d45SAlexander Motin struct eventtimer *et; 89243fe7d45SAlexander Motin int error; 89343fe7d45SAlexander Motin 89443fe7d45SAlexander Motin ET_LOCK(); 895a157e425SAlexander Motin et = timer; 89643fe7d45SAlexander Motin snprintf(buf, sizeof(buf), "%s", et->et_name); 89743fe7d45SAlexander Motin ET_UNLOCK(); 89843fe7d45SAlexander Motin error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 89943fe7d45SAlexander Motin ET_LOCK(); 900a157e425SAlexander Motin et = timer; 90143fe7d45SAlexander Motin if (error != 0 || req->newptr == NULL || 902a157e425SAlexander Motin strcasecmp(buf, et->et_name) == 0) { 90343fe7d45SAlexander Motin ET_UNLOCK(); 90443fe7d45SAlexander Motin return (error); 90543fe7d45SAlexander Motin } 906a157e425SAlexander Motin et = et_find(buf, 0, 0); 90743fe7d45SAlexander Motin if (et == NULL) { 90843fe7d45SAlexander Motin ET_UNLOCK(); 90943fe7d45SAlexander Motin return (ENOENT); 91043fe7d45SAlexander Motin } 91143fe7d45SAlexander Motin configtimer(0); 912a157e425SAlexander Motin et_free(timer); 913a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_C3STOP) 914a157e425SAlexander Motin cpu_disable_deep_sleep++; 915a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 916a157e425SAlexander Motin cpu_disable_deep_sleep--; 917afe41f2dSAlexander Motin periodic = want_periodic; 918a157e425SAlexander Motin timer = et; 919a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 92043fe7d45SAlexander Motin configtimer(1); 92143fe7d45SAlexander Motin ET_UNLOCK(); 92243fe7d45SAlexander Motin return (error); 92343fe7d45SAlexander Motin } 924a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer, 92543fe7d45SAlexander Motin CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 926dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_timer, "A", "Chosen event timer"); 927a157e425SAlexander Motin 928a157e425SAlexander Motin /* 929a157e425SAlexander Motin * Report or change the active event timer periodicity. 930a157e425SAlexander Motin */ 931a157e425SAlexander Motin static int 932a157e425SAlexander Motin sysctl_kern_eventtimer_periodic(SYSCTL_HANDLER_ARGS) 933a157e425SAlexander Motin { 934a157e425SAlexander Motin int error, val; 935a157e425SAlexander Motin 936a157e425SAlexander Motin val = periodic; 937a157e425SAlexander Motin error = sysctl_handle_int(oidp, &val, 0, req); 938a157e425SAlexander Motin if (error != 0 || req->newptr == NULL) 939a157e425SAlexander Motin return (error); 940a157e425SAlexander Motin ET_LOCK(); 941a157e425SAlexander Motin configtimer(0); 942afe41f2dSAlexander Motin periodic = want_periodic = val; 943a157e425SAlexander Motin configtimer(1); 944a157e425SAlexander Motin ET_UNLOCK(); 945a157e425SAlexander Motin return (error); 946a157e425SAlexander Motin } 947a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, periodic, 948a157e425SAlexander Motin CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 949dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_periodic, "I", "Enable event timer periodic mode"); 950