143fe7d45SAlexander Motin /*- 25b999a6bSDavide 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 3643fe7d45SAlexander Motin #include <sys/param.h> 3743fe7d45SAlexander Motin #include <sys/systm.h> 3843fe7d45SAlexander Motin #include <sys/bus.h> 395b999a6bSDavide Italiano #include <sys/limits.h> 4043fe7d45SAlexander Motin #include <sys/lock.h> 4143fe7d45SAlexander Motin #include <sys/kdb.h> 42a157e425SAlexander Motin #include <sys/ktr.h> 4343fe7d45SAlexander Motin #include <sys/mutex.h> 4443fe7d45SAlexander Motin #include <sys/proc.h> 4543fe7d45SAlexander Motin #include <sys/kernel.h> 4643fe7d45SAlexander Motin #include <sys/sched.h> 4743fe7d45SAlexander Motin #include <sys/smp.h> 4843fe7d45SAlexander Motin #include <sys/sysctl.h> 4943fe7d45SAlexander Motin #include <sys/timeet.h> 500e189873SAlexander Motin #include <sys/timetc.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> 59dd7498aeSAndriy Gapon cyclic_clock_func_t cyclic_clock_func = NULL; 6043fe7d45SAlexander Motin #endif 6143fe7d45SAlexander Motin 62a49399a9SJung-uk Kim int cpu_can_deep_sleep = 0; /* C3 state is available. */ 63a157e425SAlexander Motin int cpu_disable_deep_sleep = 0; /* Timer dies in C3. */ 6443fe7d45SAlexander Motin 65a157e425SAlexander Motin static void setuptimer(void); 665b999a6bSDavide Italiano static void loadtimer(sbintime_t now, int first); 67a157e425SAlexander Motin static int doconfigtimer(void); 68a157e425SAlexander Motin static void configtimer(int start); 69a157e425SAlexander Motin static int round_freq(struct eventtimer *et, int freq); 7043fe7d45SAlexander Motin 715b999a6bSDavide Italiano static sbintime_t getnextcpuevent(int idle); 725b999a6bSDavide Italiano static sbintime_t getnextevent(void); 735b999a6bSDavide Italiano static int handleevents(sbintime_t now, int fake); 7443fe7d45SAlexander Motin 75a157e425SAlexander Motin static struct mtx et_hw_mtx; 76a157e425SAlexander Motin 77a157e425SAlexander Motin #define ET_HW_LOCK(state) \ 78a157e425SAlexander Motin { \ 79a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 80a157e425SAlexander Motin mtx_lock_spin(&(state)->et_hw_mtx); \ 81a157e425SAlexander Motin else \ 82a157e425SAlexander Motin mtx_lock_spin(&et_hw_mtx); \ 83a157e425SAlexander Motin } 84a157e425SAlexander Motin 85a157e425SAlexander Motin #define ET_HW_UNLOCK(state) \ 86a157e425SAlexander Motin { \ 87a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 88a157e425SAlexander Motin mtx_unlock_spin(&(state)->et_hw_mtx); \ 89a157e425SAlexander Motin else \ 90a157e425SAlexander Motin mtx_unlock_spin(&et_hw_mtx); \ 91a157e425SAlexander Motin } 92a157e425SAlexander Motin 93a157e425SAlexander Motin static struct eventtimer *timer = NULL; 945b999a6bSDavide Italiano static sbintime_t timerperiod; /* Timer period for periodic mode. */ 955b999a6bSDavide Italiano static sbintime_t statperiod; /* statclock() events period. */ 965b999a6bSDavide Italiano static sbintime_t profperiod; /* profclock() events period. */ 975b999a6bSDavide Italiano static sbintime_t nexttick; /* Next global timer tick time. */ 985b999a6bSDavide Italiano static u_int busy = 1; /* Reconfiguration is in progress. */ 99*af3b2549SHans Petter Selasky static int profiling; /* Profiling events enabled. */ 100a157e425SAlexander Motin 101a157e425SAlexander Motin static char timername[32]; /* Wanted timer. */ 102a157e425SAlexander Motin TUNABLE_STR("kern.eventtimer.timer", timername, sizeof(timername)); 103a157e425SAlexander Motin 104*af3b2549SHans Petter Selasky static int singlemul; /* Multiplier for periodic mode. */ 105*af3b2549SHans Petter Selasky SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RWTUN, &singlemul, 106a157e425SAlexander Motin 0, "Multiplier for periodic mode"); 10743fe7d45SAlexander Motin 108*af3b2549SHans Petter Selasky static u_int idletick; /* Run periodic events when idle. */ 109*af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RWTUN, &idletick, 110a157e425SAlexander Motin 0, "Run periodic events when idle"); 111a157e425SAlexander Motin 112*af3b2549SHans Petter Selasky static int periodic; /* Periodic or one-shot mode. */ 113*af3b2549SHans Petter Selasky static int want_periodic; /* What mode to prefer. */ 114afe41f2dSAlexander Motin TUNABLE_INT("kern.eventtimer.periodic", &want_periodic); 115a157e425SAlexander Motin 116a157e425SAlexander Motin struct pcpu_state { 117a157e425SAlexander Motin struct mtx et_hw_mtx; /* Per-CPU timer mutex. */ 118a157e425SAlexander Motin u_int action; /* Reconfiguration requests. */ 119a157e425SAlexander Motin u_int handle; /* Immediate handle resuests. */ 1205b999a6bSDavide Italiano sbintime_t now; /* Last tick time. */ 1215b999a6bSDavide Italiano sbintime_t nextevent; /* Next scheduled event on this CPU. */ 1225b999a6bSDavide Italiano sbintime_t nexttick; /* Next timer tick time. */ 1235b999a6bSDavide Italiano sbintime_t nexthard; /* Next hardlock() event. */ 1245b999a6bSDavide Italiano sbintime_t nextstat; /* Next statclock() event. */ 1255b999a6bSDavide Italiano sbintime_t nextprof; /* Next profclock() event. */ 1265b999a6bSDavide Italiano sbintime_t nextcall; /* Next callout event. */ 1275b999a6bSDavide Italiano sbintime_t nextcallopt; /* Next optional callout event. */ 128dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 1295b999a6bSDavide Italiano sbintime_t nextcyc; /* Next OpenSolaris cyclics event. */ 130dd7498aeSAndriy Gapon #endif 131a157e425SAlexander Motin int ipi; /* This CPU needs IPI. */ 132a157e425SAlexander Motin int idle; /* This CPU is in idle mode. */ 133a157e425SAlexander Motin }; 134a157e425SAlexander Motin 1353e288e62SDimitry Andric static DPCPU_DEFINE(struct pcpu_state, timerstate); 1365b999a6bSDavide Italiano DPCPU_DEFINE(sbintime_t, hardclocktime); 137fdc5dd2dSAlexander Motin 138a157e425SAlexander Motin /* 139a157e425SAlexander Motin * Timer broadcast IPI handler. 140a157e425SAlexander Motin */ 141a157e425SAlexander Motin int 142a157e425SAlexander Motin hardclockintr(void) 14343fe7d45SAlexander Motin { 1445b999a6bSDavide Italiano sbintime_t now; 145a157e425SAlexander Motin struct pcpu_state *state; 146a157e425SAlexander Motin int done; 14743fe7d45SAlexander Motin 148a157e425SAlexander Motin if (doconfigtimer() || busy) 149a157e425SAlexander Motin return (FILTER_HANDLED); 150a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 151a157e425SAlexander Motin now = state->now; 1525b999a6bSDavide Italiano CTR3(KTR_SPARE2, "ipi at %d: now %d.%08x", 1535b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 1545b999a6bSDavide Italiano done = handleevents(now, 0); 155a157e425SAlexander Motin return (done ? FILTER_HANDLED : FILTER_STRAY); 156a157e425SAlexander Motin } 157a157e425SAlexander Motin 158a157e425SAlexander Motin /* 159a157e425SAlexander Motin * Handle all events for specified time on this CPU 160a157e425SAlexander Motin */ 161a157e425SAlexander Motin static int 1625b999a6bSDavide Italiano handleevents(sbintime_t now, int fake) 163a157e425SAlexander Motin { 1645b999a6bSDavide Italiano sbintime_t t, *hct; 165a157e425SAlexander Motin struct trapframe *frame; 166a157e425SAlexander Motin struct pcpu_state *state; 167a157e425SAlexander Motin int usermode; 168a157e425SAlexander Motin int done, runs; 169a157e425SAlexander Motin 1705b999a6bSDavide Italiano CTR3(KTR_SPARE2, "handle at %d: now %d.%08x", 1715b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 172a157e425SAlexander Motin done = 0; 173a157e425SAlexander Motin if (fake) { 174a157e425SAlexander Motin frame = NULL; 175a157e425SAlexander Motin usermode = 0; 176a157e425SAlexander Motin } else { 177a157e425SAlexander Motin frame = curthread->td_intr_frame; 178a157e425SAlexander Motin usermode = TRAPF_USERMODE(frame); 179a157e425SAlexander Motin } 180dd7498aeSAndriy Gapon 181a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 182dd7498aeSAndriy Gapon 183bcfd016cSAlexander Motin runs = 0; 1845b999a6bSDavide Italiano while (now >= state->nexthard) { 1855b999a6bSDavide Italiano state->nexthard += tick_sbt; 186a157e425SAlexander Motin runs++; 18743fe7d45SAlexander Motin } 188c0722d20SAlexander Motin if (runs) { 1895b999a6bSDavide Italiano hct = DPCPU_PTR(hardclocktime); 1905b999a6bSDavide Italiano *hct = state->nexthard - tick_sbt; 191c0722d20SAlexander Motin if (fake < 2) { 192bcfd016cSAlexander Motin hardclock_cnt(runs, usermode); 193a157e425SAlexander Motin done = 1; 19443fe7d45SAlexander Motin } 195c0722d20SAlexander Motin } 196bcfd016cSAlexander Motin runs = 0; 1975b999a6bSDavide Italiano while (now >= state->nextstat) { 1985b999a6bSDavide Italiano state->nextstat += statperiod; 199bcfd016cSAlexander Motin runs++; 200bcfd016cSAlexander Motin } 201bcfd016cSAlexander Motin if (runs && fake < 2) { 202bcfd016cSAlexander Motin statclock_cnt(runs, usermode); 203a157e425SAlexander Motin done = 1; 20443fe7d45SAlexander Motin } 205a157e425SAlexander Motin if (profiling) { 206bcfd016cSAlexander Motin runs = 0; 2075b999a6bSDavide Italiano while (now >= state->nextprof) { 2085b999a6bSDavide Italiano state->nextprof += profperiod; 209bcfd016cSAlexander Motin runs++; 210bcfd016cSAlexander Motin } 211bcfd016cSAlexander Motin if (runs && !fake) { 2125b999a6bSDavide Italiano profclock_cnt(runs, usermode, TRAPF_PC(frame)); 213a157e425SAlexander Motin done = 1; 21443fe7d45SAlexander Motin } 215a157e425SAlexander Motin } else 216a157e425SAlexander Motin state->nextprof = state->nextstat; 2175b999a6bSDavide Italiano if (now >= state->nextcallopt) { 2184bc38a5aSDavide Italiano state->nextcall = state->nextcallopt = SBT_MAX; 2195b999a6bSDavide Italiano callout_process(now); 2205b999a6bSDavide Italiano } 221dd7498aeSAndriy Gapon 222dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 2235b999a6bSDavide Italiano if (fake == 0 && now >= state->nextcyc && cyclic_clock_func != NULL) { 2244bc38a5aSDavide Italiano state->nextcyc = SBT_MAX; 225dd7498aeSAndriy Gapon (*cyclic_clock_func)(frame); 226dd7498aeSAndriy Gapon } 227dd7498aeSAndriy Gapon #endif 228dd7498aeSAndriy Gapon 2295b999a6bSDavide Italiano t = getnextcpuevent(0); 230a157e425SAlexander Motin ET_HW_LOCK(state); 231a157e425SAlexander Motin if (!busy) { 232a157e425SAlexander Motin state->idle = 0; 233a157e425SAlexander Motin state->nextevent = t; 234e37e08c7SAlexander Motin loadtimer(now, (fake == 2) && 235e37e08c7SAlexander Motin (timer->et_flags & ET_FLAGS_PERCPU)); 23643fe7d45SAlexander Motin } 237a157e425SAlexander Motin ET_HW_UNLOCK(state); 238a157e425SAlexander Motin return (done); 23943fe7d45SAlexander Motin } 24043fe7d45SAlexander Motin 24143fe7d45SAlexander Motin /* 242a157e425SAlexander Motin * Schedule binuptime of the next event on current CPU. 24343fe7d45SAlexander Motin */ 2445b999a6bSDavide Italiano static sbintime_t 2455b999a6bSDavide Italiano getnextcpuevent(int idle) 24643fe7d45SAlexander Motin { 2475b999a6bSDavide Italiano sbintime_t event; 248a157e425SAlexander Motin struct pcpu_state *state; 2495b999a6bSDavide Italiano u_int hardfreq; 25043fe7d45SAlexander Motin 251a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 2525b999a6bSDavide Italiano /* Handle hardclock() events, skipping some if CPU is idle. */ 2535b999a6bSDavide Italiano event = state->nexthard; 2545b999a6bSDavide Italiano if (idle) { 2555b999a6bSDavide Italiano hardfreq = (u_int)hz / 2; 2565b999a6bSDavide Italiano if (tc_min_ticktock_freq > 2 2575b999a6bSDavide Italiano #ifdef SMP 2585b999a6bSDavide Italiano && curcpu == CPU_FIRST() 2595b999a6bSDavide Italiano #endif 2605b999a6bSDavide Italiano ) 2615b999a6bSDavide Italiano hardfreq = hz / tc_min_ticktock_freq; 2625b999a6bSDavide Italiano if (hardfreq > 1) 2635b999a6bSDavide Italiano event += tick_sbt * (hardfreq - 1); 264fd053faeSAlexander Motin } 2655b999a6bSDavide Italiano /* Handle callout events. */ 2665b999a6bSDavide Italiano if (event > state->nextcall) 2675b999a6bSDavide Italiano event = state->nextcall; 268fd053faeSAlexander Motin if (!idle) { /* If CPU is active - handle other types of events. */ 2695b999a6bSDavide Italiano if (event > state->nextstat) 2705b999a6bSDavide Italiano event = state->nextstat; 2715b999a6bSDavide Italiano if (profiling && event > state->nextprof) 2725b999a6bSDavide Italiano event = state->nextprof; 27343fe7d45SAlexander Motin } 274dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 2755b999a6bSDavide Italiano if (event > state->nextcyc) 2765b999a6bSDavide Italiano event = state->nextcyc; 277dd7498aeSAndriy Gapon #endif 2785b999a6bSDavide Italiano return (event); 27943fe7d45SAlexander Motin } 280a157e425SAlexander Motin 281a157e425SAlexander Motin /* 282a157e425SAlexander Motin * Schedule binuptime of the next event on all CPUs. 283a157e425SAlexander Motin */ 2845b999a6bSDavide Italiano static sbintime_t 2855b999a6bSDavide Italiano getnextevent(void) 286a157e425SAlexander Motin { 287a157e425SAlexander Motin struct pcpu_state *state; 2885b999a6bSDavide Italiano sbintime_t event; 289a157e425SAlexander Motin #ifdef SMP 290a157e425SAlexander Motin int cpu; 291a157e425SAlexander Motin #endif 2925b999a6bSDavide Italiano int c; 293a157e425SAlexander Motin 294a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 2955b999a6bSDavide Italiano event = state->nextevent; 2965b999a6bSDavide Italiano c = -1; 297fd053faeSAlexander Motin #ifdef SMP 2985b999a6bSDavide Italiano if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) { 299a157e425SAlexander Motin CPU_FOREACH(cpu) { 300a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 3015b999a6bSDavide Italiano if (event > state->nextevent) { 3025b999a6bSDavide Italiano event = state->nextevent; 303a157e425SAlexander Motin c = cpu; 30443fe7d45SAlexander Motin } 30543fe7d45SAlexander Motin } 3062d7d1642SGrzegorz Bernacki } 307a157e425SAlexander Motin #endif 3085b999a6bSDavide Italiano CTR4(KTR_SPARE2, "next at %d: next %d.%08x by %d", 3095b999a6bSDavide Italiano curcpu, (int)(event >> 32), (u_int)(event & 0xffffffff), c); 3105b999a6bSDavide Italiano return (event); 311a157e425SAlexander Motin } 312a157e425SAlexander Motin 313a157e425SAlexander Motin /* Hardware timer callback function. */ 314a157e425SAlexander Motin static void 315a157e425SAlexander Motin timercb(struct eventtimer *et, void *arg) 316a157e425SAlexander Motin { 3175b999a6bSDavide Italiano sbintime_t now; 3185b999a6bSDavide Italiano sbintime_t *next; 319a157e425SAlexander Motin struct pcpu_state *state; 320a157e425SAlexander Motin #ifdef SMP 321a157e425SAlexander Motin int cpu, bcast; 322a157e425SAlexander Motin #endif 323a157e425SAlexander Motin 324a157e425SAlexander Motin /* Do not touch anything if somebody reconfiguring timers. */ 325a157e425SAlexander Motin if (busy) 326a157e425SAlexander Motin return; 327a157e425SAlexander Motin /* Update present and next tick times. */ 328a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 329a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_PERCPU) { 330a157e425SAlexander Motin next = &state->nexttick; 331a157e425SAlexander Motin } else 332a157e425SAlexander Motin next = &nexttick; 3335b999a6bSDavide Italiano now = sbinuptime(); 3345b999a6bSDavide Italiano if (periodic) 3355b999a6bSDavide Italiano *next = now + timerperiod; 3365b999a6bSDavide Italiano else 3375b999a6bSDavide Italiano *next = -1; /* Next tick is not scheduled yet. */ 338a157e425SAlexander Motin state->now = now; 3395b999a6bSDavide Italiano CTR3(KTR_SPARE2, "intr at %d: now %d.%08x", 3405b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 341a157e425SAlexander Motin 342a157e425SAlexander Motin #ifdef SMP 343a157e425SAlexander Motin /* Prepare broadcasting to other CPUs for non-per-CPU timers. */ 344a157e425SAlexander Motin bcast = 0; 345a157e425SAlexander Motin if ((et->et_flags & ET_FLAGS_PERCPU) == 0 && smp_started) { 346a157e425SAlexander Motin CPU_FOREACH(cpu) { 347a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 348a157e425SAlexander Motin ET_HW_LOCK(state); 349a157e425SAlexander Motin state->now = now; 3505b999a6bSDavide Italiano if (now >= state->nextevent) { 3515b999a6bSDavide Italiano state->nextevent += SBT_1S; 3528e860de4SAlexander Motin if (curcpu != cpu) { 353a157e425SAlexander Motin state->ipi = 1; 354a157e425SAlexander Motin bcast = 1; 355a157e425SAlexander Motin } 3568e860de4SAlexander Motin } 357a157e425SAlexander Motin ET_HW_UNLOCK(state); 358a157e425SAlexander Motin } 359a157e425SAlexander Motin } 360a157e425SAlexander Motin #endif 361a157e425SAlexander Motin 362a157e425SAlexander Motin /* Handle events for this time on this CPU. */ 3635b999a6bSDavide Italiano handleevents(now, 0); 364a157e425SAlexander Motin 365a157e425SAlexander Motin #ifdef SMP 366a157e425SAlexander Motin /* Broadcast interrupt to other CPUs for non-per-CPU timers. */ 367a157e425SAlexander Motin if (bcast) { 368a157e425SAlexander Motin CPU_FOREACH(cpu) { 369a157e425SAlexander Motin if (curcpu == cpu) 370a157e425SAlexander Motin continue; 371a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 372a157e425SAlexander Motin if (state->ipi) { 373a157e425SAlexander Motin state->ipi = 0; 374a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 375a157e425SAlexander Motin } 376a157e425SAlexander Motin } 377a157e425SAlexander Motin } 378a157e425SAlexander Motin #endif 379a157e425SAlexander Motin } 380a157e425SAlexander Motin 381a157e425SAlexander Motin /* 382a157e425SAlexander Motin * Load new value into hardware timer. 383a157e425SAlexander Motin */ 384a157e425SAlexander Motin static void 3855b999a6bSDavide Italiano loadtimer(sbintime_t now, int start) 386a157e425SAlexander Motin { 387a157e425SAlexander Motin struct pcpu_state *state; 3885b999a6bSDavide Italiano sbintime_t new; 3895b999a6bSDavide Italiano sbintime_t *next; 390a157e425SAlexander Motin uint64_t tmp; 391a157e425SAlexander Motin int eq; 392a157e425SAlexander Motin 393c70410e6SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) { 394c70410e6SAlexander Motin state = DPCPU_PTR(timerstate); 395c70410e6SAlexander Motin next = &state->nexttick; 396c70410e6SAlexander Motin } else 397c70410e6SAlexander Motin next = &nexttick; 398a157e425SAlexander Motin if (periodic) { 399a157e425SAlexander Motin if (start) { 400a157e425SAlexander Motin /* 401a157e425SAlexander Motin * Try to start all periodic timers aligned 402a157e425SAlexander Motin * to period to make events synchronous. 403a157e425SAlexander Motin */ 4045b999a6bSDavide Italiano tmp = now % timerperiod; 4055b999a6bSDavide Italiano new = timerperiod - tmp; 4065b999a6bSDavide Italiano if (new < tmp) /* Left less then passed. */ 4075b999a6bSDavide Italiano new += timerperiod; 408a157e425SAlexander Motin CTR5(KTR_SPARE2, "load p at %d: now %d.%08x first in %d.%08x", 4095b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff), 4105b999a6bSDavide Italiano (int)(new >> 32), (u_int)(new & 0xffffffff)); 4115b999a6bSDavide Italiano *next = new + now; 4125b999a6bSDavide Italiano et_start(timer, new, timerperiod); 413a157e425SAlexander Motin } 414a157e425SAlexander Motin } else { 4155b999a6bSDavide Italiano new = getnextevent(); 4165b999a6bSDavide Italiano eq = (new == *next); 4175b999a6bSDavide Italiano CTR4(KTR_SPARE2, "load at %d: next %d.%08x eq %d", 4185b999a6bSDavide Italiano curcpu, (int)(new >> 32), (u_int)(new & 0xffffffff), eq); 419a157e425SAlexander Motin if (!eq) { 420a157e425SAlexander Motin *next = new; 4215b999a6bSDavide Italiano et_start(timer, new - now, 0); 422a157e425SAlexander Motin } 423a157e425SAlexander Motin } 424a157e425SAlexander Motin } 425a157e425SAlexander Motin 426a157e425SAlexander Motin /* 427a157e425SAlexander Motin * Prepare event timer parameters after configuration changes. 428a157e425SAlexander Motin */ 429a157e425SAlexander Motin static void 430a157e425SAlexander Motin setuptimer(void) 431a157e425SAlexander Motin { 432a157e425SAlexander Motin int freq; 433a157e425SAlexander Motin 434a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 435a157e425SAlexander Motin periodic = 0; 436a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 437a157e425SAlexander Motin periodic = 1; 438dd9595e7SAlexander Motin singlemul = MIN(MAX(singlemul, 1), 20); 439a157e425SAlexander Motin freq = hz * singlemul; 440a157e425SAlexander Motin while (freq < (profiling ? profhz : stathz)) 441a157e425SAlexander Motin freq += hz; 442a157e425SAlexander Motin freq = round_freq(timer, freq); 4435b999a6bSDavide Italiano timerperiod = SBT_1S / freq; 444a157e425SAlexander Motin } 44543fe7d45SAlexander Motin 44643fe7d45SAlexander Motin /* 44743fe7d45SAlexander Motin * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler. 44843fe7d45SAlexander Motin */ 449a157e425SAlexander Motin static int 450a157e425SAlexander Motin doconfigtimer(void) 45143fe7d45SAlexander Motin { 4525b999a6bSDavide Italiano sbintime_t now; 453a157e425SAlexander Motin struct pcpu_state *state; 45443fe7d45SAlexander Motin 455a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 456a157e425SAlexander Motin switch (atomic_load_acq_int(&state->action)) { 457a157e425SAlexander Motin case 1: 4585b999a6bSDavide Italiano now = sbinuptime(); 459a157e425SAlexander Motin ET_HW_LOCK(state); 4605b999a6bSDavide Italiano loadtimer(now, 1); 461a157e425SAlexander Motin ET_HW_UNLOCK(state); 462a157e425SAlexander Motin state->handle = 0; 463a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 464a157e425SAlexander Motin return (1); 465a157e425SAlexander Motin case 2: 466a157e425SAlexander Motin ET_HW_LOCK(state); 467a157e425SAlexander Motin et_stop(timer); 468a157e425SAlexander Motin ET_HW_UNLOCK(state); 469a157e425SAlexander Motin state->handle = 0; 470a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 471a157e425SAlexander Motin return (1); 472a157e425SAlexander Motin } 473a157e425SAlexander Motin if (atomic_readandclear_int(&state->handle) && !busy) { 4745b999a6bSDavide Italiano now = sbinuptime(); 4755b999a6bSDavide Italiano handleevents(now, 0); 47643fe7d45SAlexander Motin return (1); 47743fe7d45SAlexander Motin } 47843fe7d45SAlexander Motin return (0); 47943fe7d45SAlexander Motin } 48043fe7d45SAlexander Motin 48143fe7d45SAlexander Motin /* 48243fe7d45SAlexander Motin * Reconfigure specified timer. 48343fe7d45SAlexander Motin * For per-CPU timers use IPI to make other CPUs to reconfigure. 48443fe7d45SAlexander Motin */ 48543fe7d45SAlexander Motin static void 486a157e425SAlexander Motin configtimer(int start) 48743fe7d45SAlexander Motin { 4885b999a6bSDavide Italiano sbintime_t now, next; 489a157e425SAlexander Motin struct pcpu_state *state; 49043fe7d45SAlexander Motin int cpu; 49143fe7d45SAlexander Motin 492a157e425SAlexander Motin if (start) { 493a157e425SAlexander Motin setuptimer(); 4945b999a6bSDavide Italiano now = sbinuptime(); 4955b999a6bSDavide Italiano } else 4965b999a6bSDavide Italiano now = 0; 49743fe7d45SAlexander Motin critical_enter(); 498a157e425SAlexander Motin ET_HW_LOCK(DPCPU_PTR(timerstate)); 499a157e425SAlexander Motin if (start) { 500a157e425SAlexander Motin /* Initialize time machine parameters. */ 5015b999a6bSDavide Italiano next = now + timerperiod; 502a157e425SAlexander Motin if (periodic) 503a157e425SAlexander Motin nexttick = next; 50443fe7d45SAlexander Motin else 5055b999a6bSDavide Italiano nexttick = -1; 506a157e425SAlexander Motin CPU_FOREACH(cpu) { 507a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 508a157e425SAlexander Motin state->now = now; 5095b999a6bSDavide Italiano if (!smp_started && cpu != CPU_FIRST()) 5104bc38a5aSDavide Italiano state->nextevent = SBT_MAX; 5115b999a6bSDavide Italiano else 512a157e425SAlexander Motin state->nextevent = next; 513a157e425SAlexander Motin if (periodic) 514a157e425SAlexander Motin state->nexttick = next; 515a157e425SAlexander Motin else 5165b999a6bSDavide Italiano state->nexttick = -1; 517a157e425SAlexander Motin state->nexthard = next; 518a157e425SAlexander Motin state->nextstat = next; 519a157e425SAlexander Motin state->nextprof = next; 5205b999a6bSDavide Italiano state->nextcall = next; 5215b999a6bSDavide Italiano state->nextcallopt = next; 522a157e425SAlexander Motin hardclock_sync(cpu); 523a157e425SAlexander Motin } 524a157e425SAlexander Motin busy = 0; 525a157e425SAlexander Motin /* Start global timer or per-CPU timer of this CPU. */ 5265b999a6bSDavide Italiano loadtimer(now, 1); 527a157e425SAlexander Motin } else { 528a157e425SAlexander Motin busy = 1; 529a157e425SAlexander Motin /* Stop global timer or per-CPU timer of this CPU. */ 530a157e425SAlexander Motin et_stop(timer); 531a157e425SAlexander Motin } 532a157e425SAlexander Motin ET_HW_UNLOCK(DPCPU_PTR(timerstate)); 53343fe7d45SAlexander Motin #ifdef SMP 534a157e425SAlexander Motin /* If timer is global or there is no other CPUs yet - we are done. */ 535a157e425SAlexander Motin if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) { 53643fe7d45SAlexander Motin critical_exit(); 53743fe7d45SAlexander Motin return; 53843fe7d45SAlexander Motin } 53943fe7d45SAlexander Motin /* Set reconfigure flags for other CPUs. */ 54043fe7d45SAlexander Motin CPU_FOREACH(cpu) { 541a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 542a157e425SAlexander Motin atomic_store_rel_int(&state->action, 543a157e425SAlexander Motin (cpu == curcpu) ? 0 : ( start ? 1 : 2)); 54443fe7d45SAlexander Motin } 545a157e425SAlexander Motin /* Broadcast reconfigure IPI. */ 546a157e425SAlexander Motin ipi_all_but_self(IPI_HARDCLOCK); 54743fe7d45SAlexander Motin /* Wait for reconfiguration completed. */ 54843fe7d45SAlexander Motin restart: 54943fe7d45SAlexander Motin cpu_spinwait(); 55043fe7d45SAlexander Motin CPU_FOREACH(cpu) { 55143fe7d45SAlexander Motin if (cpu == curcpu) 55243fe7d45SAlexander Motin continue; 553a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 554a157e425SAlexander Motin if (atomic_load_acq_int(&state->action)) 55543fe7d45SAlexander Motin goto restart; 55643fe7d45SAlexander Motin } 55743fe7d45SAlexander Motin #endif 558a157e425SAlexander Motin critical_exit(); 55943fe7d45SAlexander Motin } 56043fe7d45SAlexander Motin 561a157e425SAlexander Motin /* 562a157e425SAlexander Motin * Calculate nearest frequency supported by hardware timer. 563a157e425SAlexander Motin */ 56451636352SAlexander Motin static int 56551636352SAlexander Motin round_freq(struct eventtimer *et, int freq) 56651636352SAlexander Motin { 56751636352SAlexander Motin uint64_t div; 56851636352SAlexander Motin 56951636352SAlexander Motin if (et->et_frequency != 0) { 570599cf0f1SAlexander Motin div = lmax((et->et_frequency + freq / 2) / freq, 1); 57151636352SAlexander Motin if (et->et_flags & ET_FLAGS_POW2DIV) 57251636352SAlexander Motin div = 1 << (flsl(div + div / 2) - 1); 57351636352SAlexander Motin freq = (et->et_frequency + div / 2) / div; 57451636352SAlexander Motin } 575fdc5dd2dSAlexander Motin if (et->et_min_period > SBT_1S) 576803a9b3eSAlexander Motin panic("Event timer \"%s\" doesn't support sub-second periods!", 577803a9b3eSAlexander Motin et->et_name); 578fdc5dd2dSAlexander Motin else if (et->et_min_period != 0) 579fdc5dd2dSAlexander Motin freq = min(freq, SBT2FREQ(et->et_min_period)); 580fdc5dd2dSAlexander Motin if (et->et_max_period < SBT_1S && et->et_max_period != 0) 581fdc5dd2dSAlexander Motin freq = max(freq, SBT2FREQ(et->et_max_period)); 58251636352SAlexander Motin return (freq); 58351636352SAlexander Motin } 58451636352SAlexander Motin 58543fe7d45SAlexander Motin /* 586a157e425SAlexander Motin * Configure and start event timers (BSP part). 58743fe7d45SAlexander Motin */ 58843fe7d45SAlexander Motin void 58943fe7d45SAlexander Motin cpu_initclocks_bsp(void) 59043fe7d45SAlexander Motin { 591a157e425SAlexander Motin struct pcpu_state *state; 592a157e425SAlexander Motin int base, div, cpu; 59343fe7d45SAlexander Motin 594a157e425SAlexander Motin mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 595a157e425SAlexander Motin CPU_FOREACH(cpu) { 596a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 597a157e425SAlexander Motin mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 598dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 5994bc38a5aSDavide Italiano state->nextcyc = SBT_MAX; 600dd7498aeSAndriy Gapon #endif 6014bc38a5aSDavide Italiano state->nextcall = SBT_MAX; 6024bc38a5aSDavide Italiano state->nextcallopt = SBT_MAX; 603a157e425SAlexander Motin } 604afe41f2dSAlexander Motin periodic = want_periodic; 605a157e425SAlexander Motin /* Grab requested timer or the best of present. */ 606a157e425SAlexander Motin if (timername[0]) 607a157e425SAlexander Motin timer = et_find(timername, 0, 0); 608a157e425SAlexander Motin if (timer == NULL && periodic) { 609a157e425SAlexander Motin timer = et_find(NULL, 61043fe7d45SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 611a157e425SAlexander Motin } 612a157e425SAlexander Motin if (timer == NULL) { 613a157e425SAlexander Motin timer = et_find(NULL, 614a157e425SAlexander Motin ET_FLAGS_ONESHOT, ET_FLAGS_ONESHOT); 615a157e425SAlexander Motin } 616a157e425SAlexander Motin if (timer == NULL && !periodic) { 617a157e425SAlexander Motin timer = et_find(NULL, 618a157e425SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 619a157e425SAlexander Motin } 620a157e425SAlexander Motin if (timer == NULL) 621a157e425SAlexander Motin panic("No usable event timer found!"); 622a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 623a157e425SAlexander Motin 624a157e425SAlexander Motin /* Adapt to timer capabilities. */ 625a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 626a157e425SAlexander Motin periodic = 0; 627a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 628a157e425SAlexander Motin periodic = 1; 629a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 630a157e425SAlexander Motin cpu_disable_deep_sleep++; 631a157e425SAlexander Motin 63243fe7d45SAlexander Motin /* 63343fe7d45SAlexander Motin * We honor the requested 'hz' value. 63443fe7d45SAlexander Motin * We want to run stathz in the neighborhood of 128hz. 63543fe7d45SAlexander Motin * We would like profhz to run as often as possible. 63643fe7d45SAlexander Motin */ 637dd9595e7SAlexander Motin if (singlemul <= 0 || singlemul > 20) { 63843fe7d45SAlexander Motin if (hz >= 1500 || (hz % 128) == 0) 63943fe7d45SAlexander Motin singlemul = 1; 64043fe7d45SAlexander Motin else if (hz >= 750) 64143fe7d45SAlexander Motin singlemul = 2; 64243fe7d45SAlexander Motin else 64343fe7d45SAlexander Motin singlemul = 4; 64443fe7d45SAlexander Motin } 645a157e425SAlexander Motin if (periodic) { 646a157e425SAlexander Motin base = round_freq(timer, hz * singlemul); 64751636352SAlexander Motin singlemul = max((base + hz / 2) / hz, 1); 64851636352SAlexander Motin hz = (base + singlemul / 2) / singlemul; 64951636352SAlexander Motin if (base <= 128) 65043fe7d45SAlexander Motin stathz = base; 65143fe7d45SAlexander Motin else { 65243fe7d45SAlexander Motin div = base / 128; 65351636352SAlexander Motin if (div >= singlemul && (div % singlemul) == 0) 65443fe7d45SAlexander Motin div++; 65543fe7d45SAlexander Motin stathz = base / div; 65643fe7d45SAlexander Motin } 65743fe7d45SAlexander Motin profhz = stathz; 65851636352SAlexander Motin while ((profhz + stathz) <= 128 * 64) 65943fe7d45SAlexander Motin profhz += stathz; 660a157e425SAlexander Motin profhz = round_freq(timer, profhz); 66143fe7d45SAlexander Motin } else { 662a157e425SAlexander Motin hz = round_freq(timer, hz); 663a157e425SAlexander Motin stathz = round_freq(timer, 127); 664a157e425SAlexander Motin profhz = round_freq(timer, stathz * 64); 66543fe7d45SAlexander Motin } 666599cf0f1SAlexander Motin tick = 1000000 / hz; 6675b999a6bSDavide Italiano tick_sbt = SBT_1S / hz; 6685b999a6bSDavide Italiano tick_bt = sbttobt(tick_sbt); 6695b999a6bSDavide Italiano statperiod = SBT_1S / stathz; 6705b999a6bSDavide Italiano profperiod = SBT_1S / profhz; 67143fe7d45SAlexander Motin ET_LOCK(); 672a157e425SAlexander Motin configtimer(1); 67343fe7d45SAlexander Motin ET_UNLOCK(); 67443fe7d45SAlexander Motin } 67543fe7d45SAlexander Motin 676a157e425SAlexander Motin /* 677a157e425SAlexander Motin * Start per-CPU event timers on APs. 678a157e425SAlexander Motin */ 67943fe7d45SAlexander Motin void 68043fe7d45SAlexander Motin cpu_initclocks_ap(void) 68143fe7d45SAlexander Motin { 6825b999a6bSDavide Italiano sbintime_t now; 683a157e425SAlexander Motin struct pcpu_state *state; 6845b999a6bSDavide Italiano struct thread *td; 68543fe7d45SAlexander Motin 686a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 6875b999a6bSDavide Italiano now = sbinuptime(); 688a157e425SAlexander Motin ET_HW_LOCK(state); 689c70410e6SAlexander Motin state->now = now; 690c70410e6SAlexander Motin hardclock_sync(curcpu); 6915b999a6bSDavide Italiano spinlock_enter(); 692a157e425SAlexander Motin ET_HW_UNLOCK(state); 6935b999a6bSDavide Italiano td = curthread; 6945b999a6bSDavide Italiano td->td_intr_nesting_level++; 6955b999a6bSDavide Italiano handleevents(state->now, 2); 6965b999a6bSDavide Italiano td->td_intr_nesting_level--; 6975b999a6bSDavide Italiano spinlock_exit(); 69843fe7d45SAlexander Motin } 69943fe7d45SAlexander Motin 700a157e425SAlexander Motin /* 701a157e425SAlexander Motin * Switch to profiling clock rates. 702a157e425SAlexander Motin */ 70343fe7d45SAlexander Motin void 70443fe7d45SAlexander Motin cpu_startprofclock(void) 70543fe7d45SAlexander Motin { 70643fe7d45SAlexander Motin 70743fe7d45SAlexander Motin ET_LOCK(); 7081af19ee4SAlexander Motin if (profiling == 0) { 709a157e425SAlexander Motin if (periodic) { 710a157e425SAlexander Motin configtimer(0); 711a157e425SAlexander Motin profiling = 1; 712a157e425SAlexander Motin configtimer(1); 713a157e425SAlexander Motin } else 714a157e425SAlexander Motin profiling = 1; 7151af19ee4SAlexander Motin } else 7161af19ee4SAlexander Motin profiling++; 71743fe7d45SAlexander Motin ET_UNLOCK(); 71843fe7d45SAlexander Motin } 71943fe7d45SAlexander Motin 720a157e425SAlexander Motin /* 721a157e425SAlexander Motin * Switch to regular clock rates. 722a157e425SAlexander Motin */ 72343fe7d45SAlexander Motin void 72443fe7d45SAlexander Motin cpu_stopprofclock(void) 72543fe7d45SAlexander Motin { 72643fe7d45SAlexander Motin 72743fe7d45SAlexander Motin ET_LOCK(); 7281af19ee4SAlexander Motin if (profiling == 1) { 729a157e425SAlexander Motin if (periodic) { 730a157e425SAlexander Motin configtimer(0); 731a157e425SAlexander Motin profiling = 0; 732a157e425SAlexander Motin configtimer(1); 733a157e425SAlexander Motin } else 734a157e425SAlexander Motin profiling = 0; 7351af19ee4SAlexander Motin } else 7361af19ee4SAlexander Motin profiling--; 73743fe7d45SAlexander Motin ET_UNLOCK(); 73843fe7d45SAlexander Motin } 73943fe7d45SAlexander Motin 740a157e425SAlexander Motin /* 741a157e425SAlexander Motin * Switch to idle mode (all ticks handled). 742a157e425SAlexander Motin */ 743acccf7d8SDavide Italiano sbintime_t 744a157e425SAlexander Motin cpu_idleclock(void) 745a157e425SAlexander Motin { 7465b999a6bSDavide Italiano sbintime_t now, t; 747a157e425SAlexander Motin struct pcpu_state *state; 748a157e425SAlexander Motin 749a157e425SAlexander Motin if (idletick || busy || 7509dfc483cSAlexander Motin (periodic && (timer->et_flags & ET_FLAGS_PERCPU)) 7519dfc483cSAlexander Motin #ifdef DEVICE_POLLING 7529dfc483cSAlexander Motin || curcpu == CPU_FIRST() 7539dfc483cSAlexander Motin #endif 7549dfc483cSAlexander Motin ) 755acccf7d8SDavide Italiano return (-1); 756a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 757a157e425SAlexander Motin if (periodic) 758a157e425SAlexander Motin now = state->now; 759a157e425SAlexander Motin else 7605b999a6bSDavide Italiano now = sbinuptime(); 7615b999a6bSDavide Italiano CTR3(KTR_SPARE2, "idle at %d: now %d.%08x", 7625b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 7635b999a6bSDavide Italiano t = getnextcpuevent(1); 764a157e425SAlexander Motin ET_HW_LOCK(state); 765a157e425SAlexander Motin state->idle = 1; 766a157e425SAlexander Motin state->nextevent = t; 767a157e425SAlexander Motin if (!periodic) 7685b999a6bSDavide Italiano loadtimer(now, 0); 769a157e425SAlexander Motin ET_HW_UNLOCK(state); 7705b999a6bSDavide Italiano return (MAX(t - now, 0)); 771a157e425SAlexander Motin } 772a157e425SAlexander Motin 773a157e425SAlexander Motin /* 774a157e425SAlexander Motin * Switch to active mode (skip empty ticks). 775a157e425SAlexander Motin */ 776a157e425SAlexander Motin void 777a157e425SAlexander Motin cpu_activeclock(void) 778a157e425SAlexander Motin { 7795b999a6bSDavide Italiano sbintime_t now; 780a157e425SAlexander Motin struct pcpu_state *state; 781a157e425SAlexander Motin struct thread *td; 782a157e425SAlexander Motin 783a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 784a157e425SAlexander Motin if (state->idle == 0 || busy) 785a157e425SAlexander Motin return; 786a157e425SAlexander Motin if (periodic) 787a157e425SAlexander Motin now = state->now; 788a157e425SAlexander Motin else 7895b999a6bSDavide Italiano now = sbinuptime(); 7905b999a6bSDavide Italiano CTR3(KTR_SPARE2, "active at %d: now %d.%08x", 7915b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 792a157e425SAlexander Motin spinlock_enter(); 793a157e425SAlexander Motin td = curthread; 794a157e425SAlexander Motin td->td_intr_nesting_level++; 7955b999a6bSDavide Italiano handleevents(now, 1); 796a157e425SAlexander Motin td->td_intr_nesting_level--; 797a157e425SAlexander Motin spinlock_exit(); 798a157e425SAlexander Motin } 799a157e425SAlexander Motin 800cfc4b56bSIan Lepore /* 801cfc4b56bSIan Lepore * Change the frequency of the given timer. This changes et->et_frequency and 802cfc4b56bSIan Lepore * if et is the active timer it reconfigures the timer on all CPUs. This is 803cfc4b56bSIan Lepore * intended to be a private interface for the use of et_change_frequency() only. 804cfc4b56bSIan Lepore */ 805cfc4b56bSIan Lepore void 806cfc4b56bSIan Lepore cpu_et_frequency(struct eventtimer *et, uint64_t newfreq) 807cfc4b56bSIan Lepore { 808cfc4b56bSIan Lepore 809cfc4b56bSIan Lepore ET_LOCK(); 810cfc4b56bSIan Lepore if (et == timer) { 811cfc4b56bSIan Lepore configtimer(0); 812cfc4b56bSIan Lepore et->et_frequency = newfreq; 813cfc4b56bSIan Lepore configtimer(1); 814cfc4b56bSIan Lepore } else 815cfc4b56bSIan Lepore et->et_frequency = newfreq; 816cfc4b56bSIan Lepore ET_UNLOCK(); 817cfc4b56bSIan Lepore } 818cfc4b56bSIan Lepore 819dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 820dd7498aeSAndriy Gapon void 8215b999a6bSDavide Italiano clocksource_cyc_set(const struct bintime *bt) 822dd7498aeSAndriy Gapon { 8235b999a6bSDavide Italiano sbintime_t now, t; 824dd7498aeSAndriy Gapon struct pcpu_state *state; 825dd7498aeSAndriy Gapon 8265b999a6bSDavide Italiano /* Do not touch anything if somebody reconfiguring timers. */ 8275b999a6bSDavide Italiano if (busy) 8285b999a6bSDavide Italiano return; 8295b999a6bSDavide Italiano t = bttosbt(*bt); 830dd7498aeSAndriy Gapon state = DPCPU_PTR(timerstate); 831dd7498aeSAndriy Gapon if (periodic) 832dd7498aeSAndriy Gapon now = state->now; 833dd7498aeSAndriy Gapon else 8345b999a6bSDavide Italiano now = sbinuptime(); 835dd7498aeSAndriy Gapon 8365b999a6bSDavide Italiano CTR5(KTR_SPARE2, "set_cyc at %d: now %d.%08x t %d.%08x", 8375b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff), 8385b999a6bSDavide Italiano (int)(t >> 32), (u_int)(t & 0xffffffff)); 839dd7498aeSAndriy Gapon 840dd7498aeSAndriy Gapon ET_HW_LOCK(state); 8415b999a6bSDavide Italiano if (t == state->nextcyc) 8425b999a6bSDavide Italiano goto done; 8435b999a6bSDavide Italiano state->nextcyc = t; 8445b999a6bSDavide Italiano if (t >= state->nextevent) 8455b999a6bSDavide Italiano goto done; 8465b999a6bSDavide Italiano state->nextevent = t; 847dd7498aeSAndriy Gapon if (!periodic) 8485b999a6bSDavide Italiano loadtimer(now, 0); 8495b999a6bSDavide Italiano done: 850dd7498aeSAndriy Gapon ET_HW_UNLOCK(state); 851dd7498aeSAndriy Gapon } 852dd7498aeSAndriy Gapon #endif 853dd7498aeSAndriy Gapon 8545b999a6bSDavide Italiano void 8555b999a6bSDavide Italiano cpu_new_callout(int cpu, sbintime_t bt, sbintime_t bt_opt) 856a157e425SAlexander Motin { 857a157e425SAlexander Motin struct pcpu_state *state; 858a157e425SAlexander Motin 8595b999a6bSDavide Italiano /* Do not touch anything if somebody reconfiguring timers. */ 8605b999a6bSDavide Italiano if (busy) 8615b999a6bSDavide Italiano return; 8625b999a6bSDavide Italiano CTR6(KTR_SPARE2, "new co at %d: on %d at %d.%08x - %d.%08x", 8635b999a6bSDavide Italiano curcpu, cpu, (int)(bt_opt >> 32), (u_int)(bt_opt & 0xffffffff), 8645b999a6bSDavide Italiano (int)(bt >> 32), (u_int)(bt & 0xffffffff)); 865a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 866a157e425SAlexander Motin ET_HW_LOCK(state); 8675b999a6bSDavide Italiano 8685b999a6bSDavide Italiano /* 8695b999a6bSDavide Italiano * If there is callout time already set earlier -- do nothing. 8705b999a6bSDavide Italiano * This check may appear redundant because we check already in 8715b999a6bSDavide Italiano * callout_process() but this double check guarantees we're safe 8725b999a6bSDavide Italiano * with respect to race conditions between interrupts execution 8735b999a6bSDavide Italiano * and scheduling. 8745b999a6bSDavide Italiano */ 8755b999a6bSDavide Italiano state->nextcallopt = bt_opt; 8765b999a6bSDavide Italiano if (bt >= state->nextcall) 8775b999a6bSDavide Italiano goto done; 8785b999a6bSDavide Italiano state->nextcall = bt; 8795b999a6bSDavide Italiano /* If there is some other event set earlier -- do nothing. */ 8805b999a6bSDavide Italiano if (bt >= state->nextevent) 8815b999a6bSDavide Italiano goto done; 8825b999a6bSDavide Italiano state->nextevent = bt; 8835b999a6bSDavide Italiano /* If timer is periodic -- there is nothing to reprogram. */ 8845b999a6bSDavide Italiano if (periodic) 8855b999a6bSDavide Italiano goto done; 8865b999a6bSDavide Italiano /* If timer is global or of the current CPU -- reprogram it. */ 8875b999a6bSDavide Italiano if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || cpu == curcpu) { 8885b999a6bSDavide Italiano loadtimer(sbinuptime(), 0); 8895b999a6bSDavide Italiano done: 890a157e425SAlexander Motin ET_HW_UNLOCK(state); 891a157e425SAlexander Motin return; 892a157e425SAlexander Motin } 8935b999a6bSDavide Italiano /* Otherwise make other CPU to reprogram it. */ 894a157e425SAlexander Motin state->handle = 1; 8955b999a6bSDavide Italiano ET_HW_UNLOCK(state); 8965b999a6bSDavide Italiano #ifdef SMP 897a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 898a157e425SAlexander Motin #endif 8995b999a6bSDavide Italiano } 900a157e425SAlexander Motin 901a157e425SAlexander Motin /* 902a157e425SAlexander Motin * Report or change the active event timers hardware. 903a157e425SAlexander Motin */ 90443fe7d45SAlexander Motin static int 905a157e425SAlexander Motin sysctl_kern_eventtimer_timer(SYSCTL_HANDLER_ARGS) 90643fe7d45SAlexander Motin { 90743fe7d45SAlexander Motin char buf[32]; 90843fe7d45SAlexander Motin struct eventtimer *et; 90943fe7d45SAlexander Motin int error; 91043fe7d45SAlexander Motin 91143fe7d45SAlexander Motin ET_LOCK(); 912a157e425SAlexander Motin et = timer; 91343fe7d45SAlexander Motin snprintf(buf, sizeof(buf), "%s", et->et_name); 91443fe7d45SAlexander Motin ET_UNLOCK(); 91543fe7d45SAlexander Motin error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 91643fe7d45SAlexander Motin ET_LOCK(); 917a157e425SAlexander Motin et = timer; 91843fe7d45SAlexander Motin if (error != 0 || req->newptr == NULL || 919a157e425SAlexander Motin strcasecmp(buf, et->et_name) == 0) { 92043fe7d45SAlexander Motin ET_UNLOCK(); 92143fe7d45SAlexander Motin return (error); 92243fe7d45SAlexander Motin } 923a157e425SAlexander Motin et = et_find(buf, 0, 0); 92443fe7d45SAlexander Motin if (et == NULL) { 92543fe7d45SAlexander Motin ET_UNLOCK(); 92643fe7d45SAlexander Motin return (ENOENT); 92743fe7d45SAlexander Motin } 92843fe7d45SAlexander Motin configtimer(0); 929a157e425SAlexander Motin et_free(timer); 930a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_C3STOP) 931a157e425SAlexander Motin cpu_disable_deep_sleep++; 932a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 933a157e425SAlexander Motin cpu_disable_deep_sleep--; 934afe41f2dSAlexander Motin periodic = want_periodic; 935a157e425SAlexander Motin timer = et; 936a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 93743fe7d45SAlexander Motin configtimer(1); 93843fe7d45SAlexander Motin ET_UNLOCK(); 93943fe7d45SAlexander Motin return (error); 94043fe7d45SAlexander Motin } 941a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer, 94243fe7d45SAlexander Motin CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 943dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_timer, "A", "Chosen event timer"); 944a157e425SAlexander Motin 945a157e425SAlexander Motin /* 946a157e425SAlexander Motin * Report or change the active event timer periodicity. 947a157e425SAlexander Motin */ 948a157e425SAlexander Motin static int 949a157e425SAlexander Motin sysctl_kern_eventtimer_periodic(SYSCTL_HANDLER_ARGS) 950a157e425SAlexander Motin { 951a157e425SAlexander Motin int error, val; 952a157e425SAlexander Motin 953a157e425SAlexander Motin val = periodic; 954a157e425SAlexander Motin error = sysctl_handle_int(oidp, &val, 0, req); 955a157e425SAlexander Motin if (error != 0 || req->newptr == NULL) 956a157e425SAlexander Motin return (error); 957a157e425SAlexander Motin ET_LOCK(); 958a157e425SAlexander Motin configtimer(0); 959afe41f2dSAlexander Motin periodic = want_periodic = val; 960a157e425SAlexander Motin configtimer(1); 961a157e425SAlexander Motin ET_UNLOCK(); 962a157e425SAlexander Motin return (error); 963a157e425SAlexander Motin } 964a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, periodic, 965a157e425SAlexander Motin CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 966dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_periodic, "I", "Enable event timer periodic mode"); 967