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 5792597e06SJohn Baldwin int cpu_deepest_sleep = 0; /* Deepest Cx state available. */ 5892597e06SJohn Baldwin int cpu_disable_c2_sleep = 0; /* Timer dies in C2. */ 5992597e06SJohn Baldwin int cpu_disable_c3_sleep = 0; /* Timer dies in C3. */ 6043fe7d45SAlexander Motin 61a157e425SAlexander Motin static void setuptimer(void); 625b999a6bSDavide Italiano static void loadtimer(sbintime_t now, int first); 63a157e425SAlexander Motin static int doconfigtimer(void); 64a157e425SAlexander Motin static void configtimer(int start); 65a157e425SAlexander Motin static int round_freq(struct eventtimer *et, int freq); 6643fe7d45SAlexander Motin 675b999a6bSDavide Italiano static sbintime_t getnextcpuevent(int idle); 685b999a6bSDavide Italiano static sbintime_t getnextevent(void); 695b999a6bSDavide Italiano static int handleevents(sbintime_t now, int fake); 7043fe7d45SAlexander Motin 71a157e425SAlexander Motin static struct mtx et_hw_mtx; 72a157e425SAlexander Motin 73a157e425SAlexander Motin #define ET_HW_LOCK(state) \ 74a157e425SAlexander Motin { \ 75a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 76a157e425SAlexander Motin mtx_lock_spin(&(state)->et_hw_mtx); \ 77a157e425SAlexander Motin else \ 78a157e425SAlexander Motin mtx_lock_spin(&et_hw_mtx); \ 79a157e425SAlexander Motin } 80a157e425SAlexander Motin 81a157e425SAlexander Motin #define ET_HW_UNLOCK(state) \ 82a157e425SAlexander Motin { \ 83a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 84a157e425SAlexander Motin mtx_unlock_spin(&(state)->et_hw_mtx); \ 85a157e425SAlexander Motin else \ 86a157e425SAlexander Motin mtx_unlock_spin(&et_hw_mtx); \ 87a157e425SAlexander Motin } 88a157e425SAlexander Motin 89a157e425SAlexander Motin static struct eventtimer *timer = NULL; 905b999a6bSDavide Italiano static sbintime_t timerperiod; /* Timer period for periodic mode. */ 915b999a6bSDavide Italiano static sbintime_t statperiod; /* statclock() events period. */ 925b999a6bSDavide Italiano static sbintime_t profperiod; /* profclock() events period. */ 935b999a6bSDavide Italiano static sbintime_t nexttick; /* Next global timer tick time. */ 945b999a6bSDavide Italiano static u_int busy = 1; /* Reconfiguration is in progress. */ 95af3b2549SHans Petter Selasky static int profiling; /* Profiling events enabled. */ 96a157e425SAlexander Motin 97a157e425SAlexander Motin static char timername[32]; /* Wanted timer. */ 98a157e425SAlexander Motin TUNABLE_STR("kern.eventtimer.timer", timername, sizeof(timername)); 99a157e425SAlexander Motin 100af3b2549SHans Petter Selasky static int singlemul; /* Multiplier for periodic mode. */ 101af3b2549SHans Petter Selasky SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RWTUN, &singlemul, 102a157e425SAlexander Motin 0, "Multiplier for periodic mode"); 10343fe7d45SAlexander Motin 104af3b2549SHans Petter Selasky static u_int idletick; /* Run periodic events when idle. */ 105af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RWTUN, &idletick, 106a157e425SAlexander Motin 0, "Run periodic events when idle"); 107a157e425SAlexander Motin 108af3b2549SHans Petter Selasky static int periodic; /* Periodic or one-shot mode. */ 109af3b2549SHans Petter Selasky static int want_periodic; /* What mode to prefer. */ 110afe41f2dSAlexander Motin TUNABLE_INT("kern.eventtimer.periodic", &want_periodic); 111a157e425SAlexander Motin 112a157e425SAlexander Motin struct pcpu_state { 113a157e425SAlexander Motin struct mtx et_hw_mtx; /* Per-CPU timer mutex. */ 114a157e425SAlexander Motin u_int action; /* Reconfiguration requests. */ 115a157e425SAlexander Motin u_int handle; /* Immediate handle resuests. */ 1165b999a6bSDavide Italiano sbintime_t now; /* Last tick time. */ 1175b999a6bSDavide Italiano sbintime_t nextevent; /* Next scheduled event on this CPU. */ 1185b999a6bSDavide Italiano sbintime_t nexttick; /* Next timer tick time. */ 119*d3e2e28eSAlexander Motin sbintime_t nexthard; /* Next hardclock() event. */ 1205b999a6bSDavide Italiano sbintime_t nextstat; /* Next statclock() event. */ 1215b999a6bSDavide Italiano sbintime_t nextprof; /* Next profclock() event. */ 1225b999a6bSDavide Italiano sbintime_t nextcall; /* Next callout event. */ 1235b999a6bSDavide Italiano sbintime_t nextcallopt; /* Next optional callout event. */ 124a157e425SAlexander Motin int ipi; /* This CPU needs IPI. */ 125a157e425SAlexander Motin int idle; /* This CPU is in idle mode. */ 126a157e425SAlexander Motin }; 127a157e425SAlexander Motin 1283e288e62SDimitry Andric static DPCPU_DEFINE(struct pcpu_state, timerstate); 1295b999a6bSDavide Italiano DPCPU_DEFINE(sbintime_t, hardclocktime); 130fdc5dd2dSAlexander Motin 131a157e425SAlexander Motin /* 132a157e425SAlexander Motin * Timer broadcast IPI handler. 133a157e425SAlexander Motin */ 134a157e425SAlexander Motin int 135a157e425SAlexander Motin hardclockintr(void) 13643fe7d45SAlexander Motin { 1375b999a6bSDavide Italiano sbintime_t now; 138a157e425SAlexander Motin struct pcpu_state *state; 139a157e425SAlexander Motin int done; 14043fe7d45SAlexander Motin 141a157e425SAlexander Motin if (doconfigtimer() || busy) 142a157e425SAlexander Motin return (FILTER_HANDLED); 143a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 144a157e425SAlexander Motin now = state->now; 1455b999a6bSDavide Italiano CTR3(KTR_SPARE2, "ipi at %d: now %d.%08x", 1465b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 1475b999a6bSDavide Italiano done = handleevents(now, 0); 148a157e425SAlexander Motin return (done ? FILTER_HANDLED : FILTER_STRAY); 149a157e425SAlexander Motin } 150a157e425SAlexander Motin 151a157e425SAlexander Motin /* 152a157e425SAlexander Motin * Handle all events for specified time on this CPU 153a157e425SAlexander Motin */ 154a157e425SAlexander Motin static int 1555b999a6bSDavide Italiano handleevents(sbintime_t now, int fake) 156a157e425SAlexander Motin { 1575b999a6bSDavide Italiano sbintime_t t, *hct; 158a157e425SAlexander Motin struct trapframe *frame; 159a157e425SAlexander Motin struct pcpu_state *state; 160a157e425SAlexander Motin int usermode; 161a157e425SAlexander Motin int done, runs; 162a157e425SAlexander Motin 1635b999a6bSDavide Italiano CTR3(KTR_SPARE2, "handle at %d: now %d.%08x", 1645b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 165a157e425SAlexander Motin done = 0; 166a157e425SAlexander Motin if (fake) { 167a157e425SAlexander Motin frame = NULL; 168a157e425SAlexander Motin usermode = 0; 169a157e425SAlexander Motin } else { 170a157e425SAlexander Motin frame = curthread->td_intr_frame; 171a157e425SAlexander Motin usermode = TRAPF_USERMODE(frame); 172a157e425SAlexander Motin } 173dd7498aeSAndriy Gapon 174a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 175dd7498aeSAndriy Gapon 176bcfd016cSAlexander Motin runs = 0; 1775b999a6bSDavide Italiano while (now >= state->nexthard) { 1785b999a6bSDavide Italiano state->nexthard += tick_sbt; 179a157e425SAlexander Motin runs++; 18043fe7d45SAlexander Motin } 181c0722d20SAlexander Motin if (runs) { 1825b999a6bSDavide Italiano hct = DPCPU_PTR(hardclocktime); 1835b999a6bSDavide Italiano *hct = state->nexthard - tick_sbt; 184c0722d20SAlexander Motin if (fake < 2) { 185bcfd016cSAlexander Motin hardclock_cnt(runs, usermode); 186a157e425SAlexander Motin done = 1; 18743fe7d45SAlexander Motin } 188c0722d20SAlexander Motin } 189bcfd016cSAlexander Motin runs = 0; 1905b999a6bSDavide Italiano while (now >= state->nextstat) { 1915b999a6bSDavide Italiano state->nextstat += statperiod; 192bcfd016cSAlexander Motin runs++; 193bcfd016cSAlexander Motin } 194bcfd016cSAlexander Motin if (runs && fake < 2) { 195bcfd016cSAlexander Motin statclock_cnt(runs, usermode); 196a157e425SAlexander Motin done = 1; 19743fe7d45SAlexander Motin } 198a157e425SAlexander Motin if (profiling) { 199bcfd016cSAlexander Motin runs = 0; 2005b999a6bSDavide Italiano while (now >= state->nextprof) { 2015b999a6bSDavide Italiano state->nextprof += profperiod; 202bcfd016cSAlexander Motin runs++; 203bcfd016cSAlexander Motin } 204bcfd016cSAlexander Motin if (runs && !fake) { 2055b999a6bSDavide Italiano profclock_cnt(runs, usermode, TRAPF_PC(frame)); 206a157e425SAlexander Motin done = 1; 20743fe7d45SAlexander Motin } 208a157e425SAlexander Motin } else 209a157e425SAlexander Motin state->nextprof = state->nextstat; 2105b999a6bSDavide Italiano if (now >= state->nextcallopt) { 2114bc38a5aSDavide Italiano state->nextcall = state->nextcallopt = SBT_MAX; 2125b999a6bSDavide Italiano callout_process(now); 2135b999a6bSDavide Italiano } 214dd7498aeSAndriy Gapon 2155b999a6bSDavide Italiano t = getnextcpuevent(0); 216a157e425SAlexander Motin ET_HW_LOCK(state); 217a157e425SAlexander Motin if (!busy) { 218a157e425SAlexander Motin state->idle = 0; 219a157e425SAlexander Motin state->nextevent = t; 220e37e08c7SAlexander Motin loadtimer(now, (fake == 2) && 221e37e08c7SAlexander Motin (timer->et_flags & ET_FLAGS_PERCPU)); 22243fe7d45SAlexander Motin } 223a157e425SAlexander Motin ET_HW_UNLOCK(state); 224a157e425SAlexander Motin return (done); 22543fe7d45SAlexander Motin } 22643fe7d45SAlexander Motin 22743fe7d45SAlexander Motin /* 228a157e425SAlexander Motin * Schedule binuptime of the next event on current CPU. 22943fe7d45SAlexander Motin */ 2305b999a6bSDavide Italiano static sbintime_t 2315b999a6bSDavide Italiano getnextcpuevent(int idle) 23243fe7d45SAlexander Motin { 2335b999a6bSDavide Italiano sbintime_t event; 234a157e425SAlexander Motin struct pcpu_state *state; 2355b999a6bSDavide Italiano u_int hardfreq; 23643fe7d45SAlexander Motin 237a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 2385b999a6bSDavide Italiano /* Handle hardclock() events, skipping some if CPU is idle. */ 2395b999a6bSDavide Italiano event = state->nexthard; 2405b999a6bSDavide Italiano if (idle) { 2415b999a6bSDavide Italiano hardfreq = (u_int)hz / 2; 2425b999a6bSDavide Italiano if (tc_min_ticktock_freq > 2 2435b999a6bSDavide Italiano #ifdef SMP 2445b999a6bSDavide Italiano && curcpu == CPU_FIRST() 2455b999a6bSDavide Italiano #endif 2465b999a6bSDavide Italiano ) 2475b999a6bSDavide Italiano hardfreq = hz / tc_min_ticktock_freq; 2485b999a6bSDavide Italiano if (hardfreq > 1) 2495b999a6bSDavide Italiano event += tick_sbt * (hardfreq - 1); 250fd053faeSAlexander Motin } 2515b999a6bSDavide Italiano /* Handle callout events. */ 2525b999a6bSDavide Italiano if (event > state->nextcall) 2535b999a6bSDavide Italiano event = state->nextcall; 254fd053faeSAlexander Motin if (!idle) { /* If CPU is active - handle other types of events. */ 2555b999a6bSDavide Italiano if (event > state->nextstat) 2565b999a6bSDavide Italiano event = state->nextstat; 2575b999a6bSDavide Italiano if (profiling && event > state->nextprof) 2585b999a6bSDavide Italiano event = state->nextprof; 25943fe7d45SAlexander Motin } 2605b999a6bSDavide Italiano return (event); 26143fe7d45SAlexander Motin } 262a157e425SAlexander Motin 263a157e425SAlexander Motin /* 264a157e425SAlexander Motin * Schedule binuptime of the next event on all CPUs. 265a157e425SAlexander Motin */ 2665b999a6bSDavide Italiano static sbintime_t 2675b999a6bSDavide Italiano getnextevent(void) 268a157e425SAlexander Motin { 269a157e425SAlexander Motin struct pcpu_state *state; 2705b999a6bSDavide Italiano sbintime_t event; 271a157e425SAlexander Motin #ifdef SMP 272a157e425SAlexander Motin int cpu; 273a157e425SAlexander Motin #endif 2745b999a6bSDavide Italiano int c; 275a157e425SAlexander Motin 276a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 2775b999a6bSDavide Italiano event = state->nextevent; 2785b999a6bSDavide Italiano c = -1; 279fd053faeSAlexander Motin #ifdef SMP 2805b999a6bSDavide Italiano if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) { 281a157e425SAlexander Motin CPU_FOREACH(cpu) { 282a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 2835b999a6bSDavide Italiano if (event > state->nextevent) { 2845b999a6bSDavide Italiano event = state->nextevent; 285a157e425SAlexander Motin c = cpu; 28643fe7d45SAlexander Motin } 28743fe7d45SAlexander Motin } 2882d7d1642SGrzegorz Bernacki } 289a157e425SAlexander Motin #endif 2905b999a6bSDavide Italiano CTR4(KTR_SPARE2, "next at %d: next %d.%08x by %d", 2915b999a6bSDavide Italiano curcpu, (int)(event >> 32), (u_int)(event & 0xffffffff), c); 2925b999a6bSDavide Italiano return (event); 293a157e425SAlexander Motin } 294a157e425SAlexander Motin 295a157e425SAlexander Motin /* Hardware timer callback function. */ 296a157e425SAlexander Motin static void 297a157e425SAlexander Motin timercb(struct eventtimer *et, void *arg) 298a157e425SAlexander Motin { 2995b999a6bSDavide Italiano sbintime_t now; 3005b999a6bSDavide Italiano sbintime_t *next; 301a157e425SAlexander Motin struct pcpu_state *state; 302a157e425SAlexander Motin #ifdef SMP 303a157e425SAlexander Motin int cpu, bcast; 304a157e425SAlexander Motin #endif 305a157e425SAlexander Motin 306a157e425SAlexander Motin /* Do not touch anything if somebody reconfiguring timers. */ 307a157e425SAlexander Motin if (busy) 308a157e425SAlexander Motin return; 309a157e425SAlexander Motin /* Update present and next tick times. */ 310a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 311a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_PERCPU) { 312a157e425SAlexander Motin next = &state->nexttick; 313a157e425SAlexander Motin } else 314a157e425SAlexander Motin next = &nexttick; 3155b999a6bSDavide Italiano now = sbinuptime(); 3165b999a6bSDavide Italiano if (periodic) 3175b999a6bSDavide Italiano *next = now + timerperiod; 3185b999a6bSDavide Italiano else 3195b999a6bSDavide Italiano *next = -1; /* Next tick is not scheduled yet. */ 320a157e425SAlexander Motin state->now = now; 3215b999a6bSDavide Italiano CTR3(KTR_SPARE2, "intr at %d: now %d.%08x", 3225b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 323a157e425SAlexander Motin 324a157e425SAlexander Motin #ifdef SMP 325a157e425SAlexander Motin /* Prepare broadcasting to other CPUs for non-per-CPU timers. */ 326a157e425SAlexander Motin bcast = 0; 327a157e425SAlexander Motin if ((et->et_flags & ET_FLAGS_PERCPU) == 0 && smp_started) { 328a157e425SAlexander Motin CPU_FOREACH(cpu) { 329a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 330a157e425SAlexander Motin ET_HW_LOCK(state); 331a157e425SAlexander Motin state->now = now; 3325b999a6bSDavide Italiano if (now >= state->nextevent) { 3335b999a6bSDavide Italiano state->nextevent += SBT_1S; 3348e860de4SAlexander Motin if (curcpu != cpu) { 335a157e425SAlexander Motin state->ipi = 1; 336a157e425SAlexander Motin bcast = 1; 337a157e425SAlexander Motin } 3388e860de4SAlexander Motin } 339a157e425SAlexander Motin ET_HW_UNLOCK(state); 340a157e425SAlexander Motin } 341a157e425SAlexander Motin } 342a157e425SAlexander Motin #endif 343a157e425SAlexander Motin 344a157e425SAlexander Motin /* Handle events for this time on this CPU. */ 3455b999a6bSDavide Italiano handleevents(now, 0); 346a157e425SAlexander Motin 347a157e425SAlexander Motin #ifdef SMP 348a157e425SAlexander Motin /* Broadcast interrupt to other CPUs for non-per-CPU timers. */ 349a157e425SAlexander Motin if (bcast) { 350a157e425SAlexander Motin CPU_FOREACH(cpu) { 351a157e425SAlexander Motin if (curcpu == cpu) 352a157e425SAlexander Motin continue; 353a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 354a157e425SAlexander Motin if (state->ipi) { 355a157e425SAlexander Motin state->ipi = 0; 356a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 357a157e425SAlexander Motin } 358a157e425SAlexander Motin } 359a157e425SAlexander Motin } 360a157e425SAlexander Motin #endif 361a157e425SAlexander Motin } 362a157e425SAlexander Motin 363a157e425SAlexander Motin /* 364a157e425SAlexander Motin * Load new value into hardware timer. 365a157e425SAlexander Motin */ 366a157e425SAlexander Motin static void 3675b999a6bSDavide Italiano loadtimer(sbintime_t now, int start) 368a157e425SAlexander Motin { 369a157e425SAlexander Motin struct pcpu_state *state; 3705b999a6bSDavide Italiano sbintime_t new; 3715b999a6bSDavide Italiano sbintime_t *next; 372a157e425SAlexander Motin uint64_t tmp; 373a157e425SAlexander Motin int eq; 374a157e425SAlexander Motin 375c70410e6SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) { 376c70410e6SAlexander Motin state = DPCPU_PTR(timerstate); 377c70410e6SAlexander Motin next = &state->nexttick; 378c70410e6SAlexander Motin } else 379c70410e6SAlexander Motin next = &nexttick; 380a157e425SAlexander Motin if (periodic) { 381a157e425SAlexander Motin if (start) { 382a157e425SAlexander Motin /* 383a157e425SAlexander Motin * Try to start all periodic timers aligned 384a157e425SAlexander Motin * to period to make events synchronous. 385a157e425SAlexander Motin */ 3865b999a6bSDavide Italiano tmp = now % timerperiod; 3875b999a6bSDavide Italiano new = timerperiod - tmp; 3885b999a6bSDavide Italiano if (new < tmp) /* Left less then passed. */ 3895b999a6bSDavide Italiano new += timerperiod; 390a157e425SAlexander Motin CTR5(KTR_SPARE2, "load p at %d: now %d.%08x first in %d.%08x", 3915b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff), 3925b999a6bSDavide Italiano (int)(new >> 32), (u_int)(new & 0xffffffff)); 3935b999a6bSDavide Italiano *next = new + now; 3945b999a6bSDavide Italiano et_start(timer, new, timerperiod); 395a157e425SAlexander Motin } 396a157e425SAlexander Motin } else { 3975b999a6bSDavide Italiano new = getnextevent(); 3985b999a6bSDavide Italiano eq = (new == *next); 3995b999a6bSDavide Italiano CTR4(KTR_SPARE2, "load at %d: next %d.%08x eq %d", 4005b999a6bSDavide Italiano curcpu, (int)(new >> 32), (u_int)(new & 0xffffffff), eq); 401a157e425SAlexander Motin if (!eq) { 402a157e425SAlexander Motin *next = new; 4035b999a6bSDavide Italiano et_start(timer, new - now, 0); 404a157e425SAlexander Motin } 405a157e425SAlexander Motin } 406a157e425SAlexander Motin } 407a157e425SAlexander Motin 408a157e425SAlexander Motin /* 409a157e425SAlexander Motin * Prepare event timer parameters after configuration changes. 410a157e425SAlexander Motin */ 411a157e425SAlexander Motin static void 412a157e425SAlexander Motin setuptimer(void) 413a157e425SAlexander Motin { 414a157e425SAlexander Motin int freq; 415a157e425SAlexander Motin 416a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 417a157e425SAlexander Motin periodic = 0; 418a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 419a157e425SAlexander Motin periodic = 1; 420dd9595e7SAlexander Motin singlemul = MIN(MAX(singlemul, 1), 20); 421a157e425SAlexander Motin freq = hz * singlemul; 422a157e425SAlexander Motin while (freq < (profiling ? profhz : stathz)) 423a157e425SAlexander Motin freq += hz; 424a157e425SAlexander Motin freq = round_freq(timer, freq); 4255b999a6bSDavide Italiano timerperiod = SBT_1S / freq; 426a157e425SAlexander Motin } 42743fe7d45SAlexander Motin 42843fe7d45SAlexander Motin /* 42943fe7d45SAlexander Motin * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler. 43043fe7d45SAlexander Motin */ 431a157e425SAlexander Motin static int 432a157e425SAlexander Motin doconfigtimer(void) 43343fe7d45SAlexander Motin { 4345b999a6bSDavide Italiano sbintime_t now; 435a157e425SAlexander Motin struct pcpu_state *state; 43643fe7d45SAlexander Motin 437a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 438a157e425SAlexander Motin switch (atomic_load_acq_int(&state->action)) { 439a157e425SAlexander Motin case 1: 4405b999a6bSDavide Italiano now = sbinuptime(); 441a157e425SAlexander Motin ET_HW_LOCK(state); 4425b999a6bSDavide Italiano loadtimer(now, 1); 443a157e425SAlexander Motin ET_HW_UNLOCK(state); 444a157e425SAlexander Motin state->handle = 0; 445a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 446a157e425SAlexander Motin return (1); 447a157e425SAlexander Motin case 2: 448a157e425SAlexander Motin ET_HW_LOCK(state); 449a157e425SAlexander Motin et_stop(timer); 450a157e425SAlexander Motin ET_HW_UNLOCK(state); 451a157e425SAlexander Motin state->handle = 0; 452a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 453a157e425SAlexander Motin return (1); 454a157e425SAlexander Motin } 455a157e425SAlexander Motin if (atomic_readandclear_int(&state->handle) && !busy) { 4565b999a6bSDavide Italiano now = sbinuptime(); 4575b999a6bSDavide Italiano handleevents(now, 0); 45843fe7d45SAlexander Motin return (1); 45943fe7d45SAlexander Motin } 46043fe7d45SAlexander Motin return (0); 46143fe7d45SAlexander Motin } 46243fe7d45SAlexander Motin 46343fe7d45SAlexander Motin /* 46443fe7d45SAlexander Motin * Reconfigure specified timer. 46543fe7d45SAlexander Motin * For per-CPU timers use IPI to make other CPUs to reconfigure. 46643fe7d45SAlexander Motin */ 46743fe7d45SAlexander Motin static void 468a157e425SAlexander Motin configtimer(int start) 46943fe7d45SAlexander Motin { 4705b999a6bSDavide Italiano sbintime_t now, next; 471a157e425SAlexander Motin struct pcpu_state *state; 47243fe7d45SAlexander Motin int cpu; 47343fe7d45SAlexander Motin 474a157e425SAlexander Motin if (start) { 475a157e425SAlexander Motin setuptimer(); 4765b999a6bSDavide Italiano now = sbinuptime(); 4775b999a6bSDavide Italiano } else 4785b999a6bSDavide Italiano now = 0; 47943fe7d45SAlexander Motin critical_enter(); 480a157e425SAlexander Motin ET_HW_LOCK(DPCPU_PTR(timerstate)); 481a157e425SAlexander Motin if (start) { 482a157e425SAlexander Motin /* Initialize time machine parameters. */ 4835b999a6bSDavide Italiano next = now + timerperiod; 484a157e425SAlexander Motin if (periodic) 485a157e425SAlexander Motin nexttick = next; 48643fe7d45SAlexander Motin else 4875b999a6bSDavide Italiano nexttick = -1; 488a157e425SAlexander Motin CPU_FOREACH(cpu) { 489a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 490a157e425SAlexander Motin state->now = now; 4915b999a6bSDavide Italiano if (!smp_started && cpu != CPU_FIRST()) 4924bc38a5aSDavide Italiano state->nextevent = SBT_MAX; 4935b999a6bSDavide Italiano else 494a157e425SAlexander Motin state->nextevent = next; 495a157e425SAlexander Motin if (periodic) 496a157e425SAlexander Motin state->nexttick = next; 497a157e425SAlexander Motin else 4985b999a6bSDavide Italiano state->nexttick = -1; 499a157e425SAlexander Motin state->nexthard = next; 500a157e425SAlexander Motin state->nextstat = next; 501a157e425SAlexander Motin state->nextprof = next; 5025b999a6bSDavide Italiano state->nextcall = next; 5035b999a6bSDavide Italiano state->nextcallopt = next; 504a157e425SAlexander Motin hardclock_sync(cpu); 505a157e425SAlexander Motin } 506a157e425SAlexander Motin busy = 0; 507a157e425SAlexander Motin /* Start global timer or per-CPU timer of this CPU. */ 5085b999a6bSDavide Italiano loadtimer(now, 1); 509a157e425SAlexander Motin } else { 510a157e425SAlexander Motin busy = 1; 511a157e425SAlexander Motin /* Stop global timer or per-CPU timer of this CPU. */ 512a157e425SAlexander Motin et_stop(timer); 513a157e425SAlexander Motin } 514a157e425SAlexander Motin ET_HW_UNLOCK(DPCPU_PTR(timerstate)); 51543fe7d45SAlexander Motin #ifdef SMP 516a157e425SAlexander Motin /* If timer is global or there is no other CPUs yet - we are done. */ 517a157e425SAlexander Motin if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) { 51843fe7d45SAlexander Motin critical_exit(); 51943fe7d45SAlexander Motin return; 52043fe7d45SAlexander Motin } 52143fe7d45SAlexander Motin /* Set reconfigure flags for other CPUs. */ 52243fe7d45SAlexander Motin CPU_FOREACH(cpu) { 523a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 524a157e425SAlexander Motin atomic_store_rel_int(&state->action, 525a157e425SAlexander Motin (cpu == curcpu) ? 0 : ( start ? 1 : 2)); 52643fe7d45SAlexander Motin } 527a157e425SAlexander Motin /* Broadcast reconfigure IPI. */ 528a157e425SAlexander Motin ipi_all_but_self(IPI_HARDCLOCK); 52943fe7d45SAlexander Motin /* Wait for reconfiguration completed. */ 53043fe7d45SAlexander Motin restart: 53143fe7d45SAlexander Motin cpu_spinwait(); 53243fe7d45SAlexander Motin CPU_FOREACH(cpu) { 53343fe7d45SAlexander Motin if (cpu == curcpu) 53443fe7d45SAlexander Motin continue; 535a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 536a157e425SAlexander Motin if (atomic_load_acq_int(&state->action)) 53743fe7d45SAlexander Motin goto restart; 53843fe7d45SAlexander Motin } 53943fe7d45SAlexander Motin #endif 540a157e425SAlexander Motin critical_exit(); 54143fe7d45SAlexander Motin } 54243fe7d45SAlexander Motin 543a157e425SAlexander Motin /* 544a157e425SAlexander Motin * Calculate nearest frequency supported by hardware timer. 545a157e425SAlexander Motin */ 54651636352SAlexander Motin static int 54751636352SAlexander Motin round_freq(struct eventtimer *et, int freq) 54851636352SAlexander Motin { 54951636352SAlexander Motin uint64_t div; 55051636352SAlexander Motin 55151636352SAlexander Motin if (et->et_frequency != 0) { 552599cf0f1SAlexander Motin div = lmax((et->et_frequency + freq / 2) / freq, 1); 55351636352SAlexander Motin if (et->et_flags & ET_FLAGS_POW2DIV) 55451636352SAlexander Motin div = 1 << (flsl(div + div / 2) - 1); 55551636352SAlexander Motin freq = (et->et_frequency + div / 2) / div; 55651636352SAlexander Motin } 557fdc5dd2dSAlexander Motin if (et->et_min_period > SBT_1S) 558803a9b3eSAlexander Motin panic("Event timer \"%s\" doesn't support sub-second periods!", 559803a9b3eSAlexander Motin et->et_name); 560fdc5dd2dSAlexander Motin else if (et->et_min_period != 0) 561fdc5dd2dSAlexander Motin freq = min(freq, SBT2FREQ(et->et_min_period)); 562fdc5dd2dSAlexander Motin if (et->et_max_period < SBT_1S && et->et_max_period != 0) 563fdc5dd2dSAlexander Motin freq = max(freq, SBT2FREQ(et->et_max_period)); 56451636352SAlexander Motin return (freq); 56551636352SAlexander Motin } 56651636352SAlexander Motin 56743fe7d45SAlexander Motin /* 568a157e425SAlexander Motin * Configure and start event timers (BSP part). 56943fe7d45SAlexander Motin */ 57043fe7d45SAlexander Motin void 57143fe7d45SAlexander Motin cpu_initclocks_bsp(void) 57243fe7d45SAlexander Motin { 573a157e425SAlexander Motin struct pcpu_state *state; 574a157e425SAlexander Motin int base, div, cpu; 57543fe7d45SAlexander Motin 576a157e425SAlexander Motin mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 577a157e425SAlexander Motin CPU_FOREACH(cpu) { 578a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 579a157e425SAlexander Motin mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 5804bc38a5aSDavide Italiano state->nextcall = SBT_MAX; 5814bc38a5aSDavide Italiano state->nextcallopt = SBT_MAX; 582a157e425SAlexander Motin } 583afe41f2dSAlexander Motin periodic = want_periodic; 584a157e425SAlexander Motin /* Grab requested timer or the best of present. */ 585a157e425SAlexander Motin if (timername[0]) 586a157e425SAlexander Motin timer = et_find(timername, 0, 0); 587a157e425SAlexander Motin if (timer == NULL && periodic) { 588a157e425SAlexander Motin timer = et_find(NULL, 58943fe7d45SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 590a157e425SAlexander Motin } 591a157e425SAlexander Motin if (timer == NULL) { 592a157e425SAlexander Motin timer = et_find(NULL, 593a157e425SAlexander Motin ET_FLAGS_ONESHOT, ET_FLAGS_ONESHOT); 594a157e425SAlexander Motin } 595a157e425SAlexander Motin if (timer == NULL && !periodic) { 596a157e425SAlexander Motin timer = et_find(NULL, 597a157e425SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 598a157e425SAlexander Motin } 599a157e425SAlexander Motin if (timer == NULL) 600a157e425SAlexander Motin panic("No usable event timer found!"); 601a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 602a157e425SAlexander Motin 603a157e425SAlexander Motin /* Adapt to timer capabilities. */ 604a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 605a157e425SAlexander Motin periodic = 0; 606a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 607a157e425SAlexander Motin periodic = 1; 608a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 60992597e06SJohn Baldwin cpu_disable_c3_sleep++; 610a157e425SAlexander Motin 61143fe7d45SAlexander Motin /* 61243fe7d45SAlexander Motin * We honor the requested 'hz' value. 61343fe7d45SAlexander Motin * We want to run stathz in the neighborhood of 128hz. 61443fe7d45SAlexander Motin * We would like profhz to run as often as possible. 61543fe7d45SAlexander Motin */ 616dd9595e7SAlexander Motin if (singlemul <= 0 || singlemul > 20) { 61743fe7d45SAlexander Motin if (hz >= 1500 || (hz % 128) == 0) 61843fe7d45SAlexander Motin singlemul = 1; 61943fe7d45SAlexander Motin else if (hz >= 750) 62043fe7d45SAlexander Motin singlemul = 2; 62143fe7d45SAlexander Motin else 62243fe7d45SAlexander Motin singlemul = 4; 62343fe7d45SAlexander Motin } 624a157e425SAlexander Motin if (periodic) { 625a157e425SAlexander Motin base = round_freq(timer, hz * singlemul); 62651636352SAlexander Motin singlemul = max((base + hz / 2) / hz, 1); 62751636352SAlexander Motin hz = (base + singlemul / 2) / singlemul; 62851636352SAlexander Motin if (base <= 128) 62943fe7d45SAlexander Motin stathz = base; 63043fe7d45SAlexander Motin else { 63143fe7d45SAlexander Motin div = base / 128; 63251636352SAlexander Motin if (div >= singlemul && (div % singlemul) == 0) 63343fe7d45SAlexander Motin div++; 63443fe7d45SAlexander Motin stathz = base / div; 63543fe7d45SAlexander Motin } 63643fe7d45SAlexander Motin profhz = stathz; 63751636352SAlexander Motin while ((profhz + stathz) <= 128 * 64) 63843fe7d45SAlexander Motin profhz += stathz; 639a157e425SAlexander Motin profhz = round_freq(timer, profhz); 64043fe7d45SAlexander Motin } else { 641a157e425SAlexander Motin hz = round_freq(timer, hz); 642a157e425SAlexander Motin stathz = round_freq(timer, 127); 643a157e425SAlexander Motin profhz = round_freq(timer, stathz * 64); 64443fe7d45SAlexander Motin } 645599cf0f1SAlexander Motin tick = 1000000 / hz; 6465b999a6bSDavide Italiano tick_sbt = SBT_1S / hz; 6475b999a6bSDavide Italiano tick_bt = sbttobt(tick_sbt); 6485b999a6bSDavide Italiano statperiod = SBT_1S / stathz; 6495b999a6bSDavide Italiano profperiod = SBT_1S / profhz; 65043fe7d45SAlexander Motin ET_LOCK(); 651a157e425SAlexander Motin configtimer(1); 65243fe7d45SAlexander Motin ET_UNLOCK(); 65343fe7d45SAlexander Motin } 65443fe7d45SAlexander Motin 655a157e425SAlexander Motin /* 656a157e425SAlexander Motin * Start per-CPU event timers on APs. 657a157e425SAlexander Motin */ 65843fe7d45SAlexander Motin void 65943fe7d45SAlexander Motin cpu_initclocks_ap(void) 66043fe7d45SAlexander Motin { 6615b999a6bSDavide Italiano sbintime_t now; 662a157e425SAlexander Motin struct pcpu_state *state; 6635b999a6bSDavide Italiano struct thread *td; 66443fe7d45SAlexander Motin 665a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 6665b999a6bSDavide Italiano now = sbinuptime(); 667a157e425SAlexander Motin ET_HW_LOCK(state); 668c70410e6SAlexander Motin state->now = now; 669c70410e6SAlexander Motin hardclock_sync(curcpu); 6705b999a6bSDavide Italiano spinlock_enter(); 671a157e425SAlexander Motin ET_HW_UNLOCK(state); 6725b999a6bSDavide Italiano td = curthread; 6735b999a6bSDavide Italiano td->td_intr_nesting_level++; 6745b999a6bSDavide Italiano handleevents(state->now, 2); 6755b999a6bSDavide Italiano td->td_intr_nesting_level--; 6765b999a6bSDavide Italiano spinlock_exit(); 67743fe7d45SAlexander Motin } 67843fe7d45SAlexander Motin 679a157e425SAlexander Motin /* 680a157e425SAlexander Motin * Switch to profiling clock rates. 681a157e425SAlexander Motin */ 68243fe7d45SAlexander Motin void 68343fe7d45SAlexander Motin cpu_startprofclock(void) 68443fe7d45SAlexander Motin { 68543fe7d45SAlexander Motin 68643fe7d45SAlexander Motin ET_LOCK(); 6871af19ee4SAlexander Motin if (profiling == 0) { 688a157e425SAlexander Motin if (periodic) { 689a157e425SAlexander Motin configtimer(0); 690a157e425SAlexander Motin profiling = 1; 691a157e425SAlexander Motin configtimer(1); 692a157e425SAlexander Motin } else 693a157e425SAlexander Motin profiling = 1; 6941af19ee4SAlexander Motin } else 6951af19ee4SAlexander Motin profiling++; 69643fe7d45SAlexander Motin ET_UNLOCK(); 69743fe7d45SAlexander Motin } 69843fe7d45SAlexander Motin 699a157e425SAlexander Motin /* 700a157e425SAlexander Motin * Switch to regular clock rates. 701a157e425SAlexander Motin */ 70243fe7d45SAlexander Motin void 70343fe7d45SAlexander Motin cpu_stopprofclock(void) 70443fe7d45SAlexander Motin { 70543fe7d45SAlexander Motin 70643fe7d45SAlexander Motin ET_LOCK(); 7071af19ee4SAlexander Motin if (profiling == 1) { 708a157e425SAlexander Motin if (periodic) { 709a157e425SAlexander Motin configtimer(0); 710a157e425SAlexander Motin profiling = 0; 711a157e425SAlexander Motin configtimer(1); 712a157e425SAlexander Motin } else 713a157e425SAlexander Motin profiling = 0; 7141af19ee4SAlexander Motin } else 7151af19ee4SAlexander Motin profiling--; 71643fe7d45SAlexander Motin ET_UNLOCK(); 71743fe7d45SAlexander Motin } 71843fe7d45SAlexander Motin 719a157e425SAlexander Motin /* 720a157e425SAlexander Motin * Switch to idle mode (all ticks handled). 721a157e425SAlexander Motin */ 722acccf7d8SDavide Italiano sbintime_t 723a157e425SAlexander Motin cpu_idleclock(void) 724a157e425SAlexander Motin { 7255b999a6bSDavide Italiano sbintime_t now, t; 726a157e425SAlexander Motin struct pcpu_state *state; 727a157e425SAlexander Motin 728a157e425SAlexander Motin if (idletick || busy || 7299dfc483cSAlexander Motin (periodic && (timer->et_flags & ET_FLAGS_PERCPU)) 7309dfc483cSAlexander Motin #ifdef DEVICE_POLLING 7319dfc483cSAlexander Motin || curcpu == CPU_FIRST() 7329dfc483cSAlexander Motin #endif 7339dfc483cSAlexander Motin ) 734acccf7d8SDavide Italiano return (-1); 735a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 736a157e425SAlexander Motin if (periodic) 737a157e425SAlexander Motin now = state->now; 738a157e425SAlexander Motin else 7395b999a6bSDavide Italiano now = sbinuptime(); 7405b999a6bSDavide Italiano CTR3(KTR_SPARE2, "idle at %d: now %d.%08x", 7415b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 7425b999a6bSDavide Italiano t = getnextcpuevent(1); 743a157e425SAlexander Motin ET_HW_LOCK(state); 744a157e425SAlexander Motin state->idle = 1; 745a157e425SAlexander Motin state->nextevent = t; 746a157e425SAlexander Motin if (!periodic) 7475b999a6bSDavide Italiano loadtimer(now, 0); 748a157e425SAlexander Motin ET_HW_UNLOCK(state); 7495b999a6bSDavide Italiano return (MAX(t - now, 0)); 750a157e425SAlexander Motin } 751a157e425SAlexander Motin 752a157e425SAlexander Motin /* 753a157e425SAlexander Motin * Switch to active mode (skip empty ticks). 754a157e425SAlexander Motin */ 755a157e425SAlexander Motin void 756a157e425SAlexander Motin cpu_activeclock(void) 757a157e425SAlexander Motin { 7585b999a6bSDavide Italiano sbintime_t now; 759a157e425SAlexander Motin struct pcpu_state *state; 760a157e425SAlexander Motin struct thread *td; 761a157e425SAlexander Motin 762a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 763a157e425SAlexander Motin if (state->idle == 0 || busy) 764a157e425SAlexander Motin return; 765a157e425SAlexander Motin if (periodic) 766a157e425SAlexander Motin now = state->now; 767a157e425SAlexander Motin else 7685b999a6bSDavide Italiano now = sbinuptime(); 7695b999a6bSDavide Italiano CTR3(KTR_SPARE2, "active at %d: now %d.%08x", 7705b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 771a157e425SAlexander Motin spinlock_enter(); 772a157e425SAlexander Motin td = curthread; 773a157e425SAlexander Motin td->td_intr_nesting_level++; 7745b999a6bSDavide Italiano handleevents(now, 1); 775a157e425SAlexander Motin td->td_intr_nesting_level--; 776a157e425SAlexander Motin spinlock_exit(); 777a157e425SAlexander Motin } 778a157e425SAlexander Motin 779cfc4b56bSIan Lepore /* 780cfc4b56bSIan Lepore * Change the frequency of the given timer. This changes et->et_frequency and 781cfc4b56bSIan Lepore * if et is the active timer it reconfigures the timer on all CPUs. This is 782cfc4b56bSIan Lepore * intended to be a private interface for the use of et_change_frequency() only. 783cfc4b56bSIan Lepore */ 784cfc4b56bSIan Lepore void 785cfc4b56bSIan Lepore cpu_et_frequency(struct eventtimer *et, uint64_t newfreq) 786cfc4b56bSIan Lepore { 787cfc4b56bSIan Lepore 788cfc4b56bSIan Lepore ET_LOCK(); 789cfc4b56bSIan Lepore if (et == timer) { 790cfc4b56bSIan Lepore configtimer(0); 791cfc4b56bSIan Lepore et->et_frequency = newfreq; 792cfc4b56bSIan Lepore configtimer(1); 793cfc4b56bSIan Lepore } else 794cfc4b56bSIan Lepore et->et_frequency = newfreq; 795cfc4b56bSIan Lepore ET_UNLOCK(); 796cfc4b56bSIan Lepore } 797cfc4b56bSIan Lepore 7985b999a6bSDavide Italiano void 7995b999a6bSDavide Italiano cpu_new_callout(int cpu, sbintime_t bt, sbintime_t bt_opt) 800a157e425SAlexander Motin { 801a157e425SAlexander Motin struct pcpu_state *state; 802a157e425SAlexander Motin 8035b999a6bSDavide Italiano /* Do not touch anything if somebody reconfiguring timers. */ 8045b999a6bSDavide Italiano if (busy) 8055b999a6bSDavide Italiano return; 8065b999a6bSDavide Italiano CTR6(KTR_SPARE2, "new co at %d: on %d at %d.%08x - %d.%08x", 8075b999a6bSDavide Italiano curcpu, cpu, (int)(bt_opt >> 32), (u_int)(bt_opt & 0xffffffff), 8085b999a6bSDavide Italiano (int)(bt >> 32), (u_int)(bt & 0xffffffff)); 809a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 810a157e425SAlexander Motin ET_HW_LOCK(state); 8115b999a6bSDavide Italiano 8125b999a6bSDavide Italiano /* 8135b999a6bSDavide Italiano * If there is callout time already set earlier -- do nothing. 8145b999a6bSDavide Italiano * This check may appear redundant because we check already in 8155b999a6bSDavide Italiano * callout_process() but this double check guarantees we're safe 8165b999a6bSDavide Italiano * with respect to race conditions between interrupts execution 8175b999a6bSDavide Italiano * and scheduling. 8185b999a6bSDavide Italiano */ 8195b999a6bSDavide Italiano state->nextcallopt = bt_opt; 8205b999a6bSDavide Italiano if (bt >= state->nextcall) 8215b999a6bSDavide Italiano goto done; 8225b999a6bSDavide Italiano state->nextcall = bt; 8235b999a6bSDavide Italiano /* If there is some other event set earlier -- do nothing. */ 8245b999a6bSDavide Italiano if (bt >= state->nextevent) 8255b999a6bSDavide Italiano goto done; 8265b999a6bSDavide Italiano state->nextevent = bt; 8275b999a6bSDavide Italiano /* If timer is periodic -- there is nothing to reprogram. */ 8285b999a6bSDavide Italiano if (periodic) 8295b999a6bSDavide Italiano goto done; 8305b999a6bSDavide Italiano /* If timer is global or of the current CPU -- reprogram it. */ 8315b999a6bSDavide Italiano if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || cpu == curcpu) { 8325b999a6bSDavide Italiano loadtimer(sbinuptime(), 0); 8335b999a6bSDavide Italiano done: 834a157e425SAlexander Motin ET_HW_UNLOCK(state); 835a157e425SAlexander Motin return; 836a157e425SAlexander Motin } 8375b999a6bSDavide Italiano /* Otherwise make other CPU to reprogram it. */ 838a157e425SAlexander Motin state->handle = 1; 8395b999a6bSDavide Italiano ET_HW_UNLOCK(state); 8405b999a6bSDavide Italiano #ifdef SMP 841a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 842a157e425SAlexander Motin #endif 8435b999a6bSDavide Italiano } 844a157e425SAlexander Motin 845a157e425SAlexander Motin /* 846a157e425SAlexander Motin * Report or change the active event timers hardware. 847a157e425SAlexander Motin */ 84843fe7d45SAlexander Motin static int 849a157e425SAlexander Motin sysctl_kern_eventtimer_timer(SYSCTL_HANDLER_ARGS) 85043fe7d45SAlexander Motin { 85143fe7d45SAlexander Motin char buf[32]; 85243fe7d45SAlexander Motin struct eventtimer *et; 85343fe7d45SAlexander Motin int error; 85443fe7d45SAlexander Motin 85543fe7d45SAlexander Motin ET_LOCK(); 856a157e425SAlexander Motin et = timer; 85743fe7d45SAlexander Motin snprintf(buf, sizeof(buf), "%s", et->et_name); 85843fe7d45SAlexander Motin ET_UNLOCK(); 85943fe7d45SAlexander Motin error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 86043fe7d45SAlexander Motin ET_LOCK(); 861a157e425SAlexander Motin et = timer; 86243fe7d45SAlexander Motin if (error != 0 || req->newptr == NULL || 863a157e425SAlexander Motin strcasecmp(buf, et->et_name) == 0) { 86443fe7d45SAlexander Motin ET_UNLOCK(); 86543fe7d45SAlexander Motin return (error); 86643fe7d45SAlexander Motin } 867a157e425SAlexander Motin et = et_find(buf, 0, 0); 86843fe7d45SAlexander Motin if (et == NULL) { 86943fe7d45SAlexander Motin ET_UNLOCK(); 87043fe7d45SAlexander Motin return (ENOENT); 87143fe7d45SAlexander Motin } 87243fe7d45SAlexander Motin configtimer(0); 873a157e425SAlexander Motin et_free(timer); 874a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_C3STOP) 87592597e06SJohn Baldwin cpu_disable_c3_sleep++; 876a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 87792597e06SJohn Baldwin cpu_disable_c3_sleep--; 878afe41f2dSAlexander Motin periodic = want_periodic; 879a157e425SAlexander Motin timer = et; 880a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 88143fe7d45SAlexander Motin configtimer(1); 88243fe7d45SAlexander Motin ET_UNLOCK(); 88343fe7d45SAlexander Motin return (error); 88443fe7d45SAlexander Motin } 885a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer, 88643fe7d45SAlexander Motin CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 887dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_timer, "A", "Chosen event timer"); 888a157e425SAlexander Motin 889a157e425SAlexander Motin /* 890a157e425SAlexander Motin * Report or change the active event timer periodicity. 891a157e425SAlexander Motin */ 892a157e425SAlexander Motin static int 893a157e425SAlexander Motin sysctl_kern_eventtimer_periodic(SYSCTL_HANDLER_ARGS) 894a157e425SAlexander Motin { 895a157e425SAlexander Motin int error, val; 896a157e425SAlexander Motin 897a157e425SAlexander Motin val = periodic; 898a157e425SAlexander Motin error = sysctl_handle_int(oidp, &val, 0, req); 899a157e425SAlexander Motin if (error != 0 || req->newptr == NULL) 900a157e425SAlexander Motin return (error); 901a157e425SAlexander Motin ET_LOCK(); 902a157e425SAlexander Motin configtimer(0); 903afe41f2dSAlexander Motin periodic = want_periodic = val; 904a157e425SAlexander Motin configtimer(1); 905a157e425SAlexander Motin ET_UNLOCK(); 906a157e425SAlexander Motin return (error); 907a157e425SAlexander Motin } 908a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, periodic, 909a157e425SAlexander Motin CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 910dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_periodic, "I", "Enable event timer periodic mode"); 9116e3bf539SKonstantin Belousov 9126e3bf539SKonstantin Belousov #include "opt_ddb.h" 9136e3bf539SKonstantin Belousov 9146e3bf539SKonstantin Belousov #ifdef DDB 9156e3bf539SKonstantin Belousov #include <ddb/ddb.h> 9166e3bf539SKonstantin Belousov 9176e3bf539SKonstantin Belousov DB_SHOW_COMMAND(clocksource, db_show_clocksource) 9186e3bf539SKonstantin Belousov { 9196e3bf539SKonstantin Belousov struct pcpu_state *st; 9206e3bf539SKonstantin Belousov int c; 9216e3bf539SKonstantin Belousov 9226e3bf539SKonstantin Belousov CPU_FOREACH(c) { 9236e3bf539SKonstantin Belousov st = DPCPU_ID_PTR(c, timerstate); 9246e3bf539SKonstantin Belousov db_printf( 9256e3bf539SKonstantin Belousov "CPU %2d: action %d handle %d ipi %d idle %d\n" 9266e3bf539SKonstantin Belousov " now %#jx nevent %#jx (%jd)\n" 9276e3bf539SKonstantin Belousov " ntick %#jx (%jd) nhard %#jx (%jd)\n" 9286e3bf539SKonstantin Belousov " nstat %#jx (%jd) nprof %#jx (%jd)\n" 9296e3bf539SKonstantin Belousov " ncall %#jx (%jd) ncallopt %#jx (%jd)\n", 9306e3bf539SKonstantin Belousov c, st->action, st->handle, st->ipi, st->idle, 9316e3bf539SKonstantin Belousov (uintmax_t)st->now, 9326e3bf539SKonstantin Belousov (uintmax_t)st->nextevent, 9336e3bf539SKonstantin Belousov (uintmax_t)(st->nextevent - st->now) / tick_sbt, 9346e3bf539SKonstantin Belousov (uintmax_t)st->nexttick, 9356e3bf539SKonstantin Belousov (uintmax_t)(st->nexttick - st->now) / tick_sbt, 9366e3bf539SKonstantin Belousov (uintmax_t)st->nexthard, 9376e3bf539SKonstantin Belousov (uintmax_t)(st->nexthard - st->now) / tick_sbt, 9386e3bf539SKonstantin Belousov (uintmax_t)st->nextstat, 9396e3bf539SKonstantin Belousov (uintmax_t)(st->nextstat - st->now) / tick_sbt, 9406e3bf539SKonstantin Belousov (uintmax_t)st->nextprof, 9416e3bf539SKonstantin Belousov (uintmax_t)(st->nextprof - st->now) / tick_sbt, 9426e3bf539SKonstantin Belousov (uintmax_t)st->nextcall, 9436e3bf539SKonstantin Belousov (uintmax_t)(st->nextcall - st->now) / tick_sbt, 9446e3bf539SKonstantin Belousov (uintmax_t)st->nextcallopt, 9456e3bf539SKonstantin Belousov (uintmax_t)(st->nextcallopt - st->now) / tick_sbt); 9466e3bf539SKonstantin Belousov } 9476e3bf539SKonstantin Belousov } 9486e3bf539SKonstantin Belousov 9496e3bf539SKonstantin Belousov #endif 950