143fe7d45SAlexander Motin /*- 2fd053faeSAlexander Motin * Copyright (c) 2010-2012 Alexander Motin <mav@FreeBSD.org> 343fe7d45SAlexander Motin * All rights reserved. 443fe7d45SAlexander Motin * 543fe7d45SAlexander Motin * Redistribution and use in source and binary forms, with or without 643fe7d45SAlexander Motin * modification, are permitted provided that the following conditions 743fe7d45SAlexander Motin * are met: 843fe7d45SAlexander Motin * 1. Redistributions of source code must retain the above copyright 943fe7d45SAlexander Motin * notice, this list of conditions and the following disclaimer, 1043fe7d45SAlexander Motin * without modification, immediately at the beginning of the file. 1143fe7d45SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright 1243fe7d45SAlexander Motin * notice, this list of conditions and the following disclaimer in the 1343fe7d45SAlexander Motin * documentation and/or other materials provided with the distribution. 1443fe7d45SAlexander Motin * 1543fe7d45SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1643fe7d45SAlexander Motin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1743fe7d45SAlexander Motin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1843fe7d45SAlexander Motin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1943fe7d45SAlexander Motin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2043fe7d45SAlexander Motin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2143fe7d45SAlexander Motin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2243fe7d45SAlexander Motin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2343fe7d45SAlexander Motin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2443fe7d45SAlexander Motin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2543fe7d45SAlexander Motin */ 2643fe7d45SAlexander Motin 2743fe7d45SAlexander Motin #include <sys/cdefs.h> 2843fe7d45SAlexander Motin __FBSDID("$FreeBSD$"); 2943fe7d45SAlexander Motin 3043fe7d45SAlexander Motin /* 3143fe7d45SAlexander Motin * Common routines to manage event timers hardware. 3243fe7d45SAlexander Motin */ 3343fe7d45SAlexander Motin 349dfc483cSAlexander Motin #include "opt_device_polling.h" 3543fe7d45SAlexander Motin #include "opt_kdtrace.h" 3643fe7d45SAlexander Motin 3743fe7d45SAlexander Motin #include <sys/param.h> 3843fe7d45SAlexander Motin #include <sys/systm.h> 3943fe7d45SAlexander Motin #include <sys/bus.h> 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); 66a157e425SAlexander Motin static void loadtimer(struct bintime *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 71a157e425SAlexander Motin static void getnextcpuevent(struct bintime *event, int idle); 72a157e425SAlexander Motin static void getnextevent(struct bintime *event); 73a157e425SAlexander Motin static int handleevents(struct bintime *now, int fake); 74a157e425SAlexander Motin #ifdef SMP 75a157e425SAlexander Motin static void cpu_new_callout(int cpu, int ticks); 76a157e425SAlexander Motin #endif 7743fe7d45SAlexander Motin 78a157e425SAlexander Motin static struct mtx et_hw_mtx; 79a157e425SAlexander Motin 80a157e425SAlexander Motin #define ET_HW_LOCK(state) \ 81a157e425SAlexander Motin { \ 82a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 83a157e425SAlexander Motin mtx_lock_spin(&(state)->et_hw_mtx); \ 84a157e425SAlexander Motin else \ 85a157e425SAlexander Motin mtx_lock_spin(&et_hw_mtx); \ 86a157e425SAlexander Motin } 87a157e425SAlexander Motin 88a157e425SAlexander Motin #define ET_HW_UNLOCK(state) \ 89a157e425SAlexander Motin { \ 90a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 91a157e425SAlexander Motin mtx_unlock_spin(&(state)->et_hw_mtx); \ 92a157e425SAlexander Motin else \ 93a157e425SAlexander Motin mtx_unlock_spin(&et_hw_mtx); \ 94a157e425SAlexander Motin } 95a157e425SAlexander Motin 96a157e425SAlexander Motin static struct eventtimer *timer = NULL; 97a157e425SAlexander Motin static struct bintime timerperiod; /* Timer period for periodic mode. */ 98a157e425SAlexander Motin static struct bintime hardperiod; /* hardclock() events period. */ 99a157e425SAlexander Motin static struct bintime statperiod; /* statclock() events period. */ 100a157e425SAlexander Motin static struct bintime profperiod; /* profclock() events period. */ 101a157e425SAlexander Motin static struct bintime nexttick; /* Next global timer tick time. */ 102fd053faeSAlexander Motin static struct bintime nexthard; /* Next global hardlock() event. */ 103a157e425SAlexander Motin static u_int busy = 0; /* Reconfiguration is in progress. */ 104a157e425SAlexander Motin static int profiling = 0; /* Profiling events enabled. */ 105a157e425SAlexander Motin 106a157e425SAlexander Motin static char timername[32]; /* Wanted timer. */ 107a157e425SAlexander Motin TUNABLE_STR("kern.eventtimer.timer", timername, sizeof(timername)); 108a157e425SAlexander Motin 109dd9595e7SAlexander Motin static int singlemul = 0; /* Multiplier for periodic mode. */ 11043fe7d45SAlexander Motin TUNABLE_INT("kern.eventtimer.singlemul", &singlemul); 11143fe7d45SAlexander Motin SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul, 112a157e425SAlexander Motin 0, "Multiplier for periodic mode"); 11343fe7d45SAlexander Motin 114fd053faeSAlexander Motin static u_int idletick = 0; /* Run periodic events when idle. */ 115a157e425SAlexander Motin TUNABLE_INT("kern.eventtimer.idletick", &idletick); 116fbbb13f9SMatthew D Fleming SYSCTL_UINT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RW, &idletick, 117a157e425SAlexander Motin 0, "Run periodic events when idle"); 118a157e425SAlexander Motin 119fd053faeSAlexander Motin static u_int activetick = 1; /* Run all periodic events when active. */ 120fd053faeSAlexander Motin TUNABLE_INT("kern.eventtimer.activetick", &activetick); 121fd053faeSAlexander Motin SYSCTL_UINT(_kern_eventtimer, OID_AUTO, activetick, CTLFLAG_RW, &activetick, 122fd053faeSAlexander Motin 0, "Run all periodic events when active"); 123fd053faeSAlexander Motin 124a157e425SAlexander Motin static int periodic = 0; /* Periodic or one-shot mode. */ 125afe41f2dSAlexander Motin static int want_periodic = 0; /* What mode to prefer. */ 126afe41f2dSAlexander Motin TUNABLE_INT("kern.eventtimer.periodic", &want_periodic); 127a157e425SAlexander Motin 128a157e425SAlexander Motin struct pcpu_state { 129a157e425SAlexander Motin struct mtx et_hw_mtx; /* Per-CPU timer mutex. */ 130a157e425SAlexander Motin u_int action; /* Reconfiguration requests. */ 131a157e425SAlexander Motin u_int handle; /* Immediate handle resuests. */ 132a157e425SAlexander Motin struct bintime now; /* Last tick time. */ 133a157e425SAlexander Motin struct bintime nextevent; /* Next scheduled event on this CPU. */ 134a157e425SAlexander Motin struct bintime nexttick; /* Next timer tick time. */ 135a157e425SAlexander Motin struct bintime nexthard; /* Next hardlock() event. */ 136a157e425SAlexander Motin struct bintime nextstat; /* Next statclock() event. */ 137a157e425SAlexander Motin struct bintime nextprof; /* Next profclock() event. */ 138dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 139dd7498aeSAndriy Gapon struct bintime nextcyc; /* Next OpenSolaris cyclics event. */ 140dd7498aeSAndriy Gapon #endif 141a157e425SAlexander Motin int ipi; /* This CPU needs IPI. */ 142a157e425SAlexander Motin int idle; /* This CPU is in idle mode. */ 143a157e425SAlexander Motin }; 144a157e425SAlexander Motin 1453e288e62SDimitry Andric static DPCPU_DEFINE(struct pcpu_state, timerstate); 14643fe7d45SAlexander Motin 14743fe7d45SAlexander Motin #define FREQ2BT(freq, bt) \ 14843fe7d45SAlexander Motin { \ 14943fe7d45SAlexander Motin (bt)->sec = 0; \ 15043fe7d45SAlexander Motin (bt)->frac = ((uint64_t)0x8000000000000000 / (freq)) << 1; \ 15143fe7d45SAlexander Motin } 15251636352SAlexander Motin #define BT2FREQ(bt) \ 15351636352SAlexander Motin (((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \ 15451636352SAlexander Motin ((bt)->frac >> 1)) 15543fe7d45SAlexander Motin 156*fdc5dd2dSAlexander Motin #define SBT2FREQ(sbt) ((SBT_1S + ((sbt) >> 1)) / (sbt)) 157*fdc5dd2dSAlexander Motin 158a157e425SAlexander Motin /* 159a157e425SAlexander Motin * Timer broadcast IPI handler. 160a157e425SAlexander Motin */ 161a157e425SAlexander Motin int 162a157e425SAlexander Motin hardclockintr(void) 16343fe7d45SAlexander Motin { 164a157e425SAlexander Motin struct bintime now; 165a157e425SAlexander Motin struct pcpu_state *state; 166a157e425SAlexander Motin int done; 16743fe7d45SAlexander Motin 168a157e425SAlexander Motin if (doconfigtimer() || busy) 169a157e425SAlexander Motin return (FILTER_HANDLED); 170a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 171a157e425SAlexander Motin now = state->now; 172a157e425SAlexander Motin CTR4(KTR_SPARE2, "ipi at %d: now %d.%08x%08x", 1739b71c63aSAlexander Motin curcpu, now.sec, (u_int)(now.frac >> 32), 1749b71c63aSAlexander Motin (u_int)(now.frac & 0xffffffff)); 175a157e425SAlexander Motin done = handleevents(&now, 0); 176a157e425SAlexander Motin return (done ? FILTER_HANDLED : FILTER_STRAY); 177a157e425SAlexander Motin } 178a157e425SAlexander Motin 179a157e425SAlexander Motin /* 180a157e425SAlexander Motin * Handle all events for specified time on this CPU 181a157e425SAlexander Motin */ 182a157e425SAlexander Motin static int 183a157e425SAlexander Motin handleevents(struct bintime *now, int fake) 184a157e425SAlexander Motin { 185a157e425SAlexander Motin struct bintime t; 186a157e425SAlexander Motin struct trapframe *frame; 187a157e425SAlexander Motin struct pcpu_state *state; 188a157e425SAlexander Motin uintfptr_t pc; 189a157e425SAlexander Motin int usermode; 190a157e425SAlexander Motin int done, runs; 191a157e425SAlexander Motin 192a157e425SAlexander Motin CTR4(KTR_SPARE2, "handle at %d: now %d.%08x%08x", 1939b71c63aSAlexander Motin curcpu, now->sec, (u_int)(now->frac >> 32), 1949b71c63aSAlexander Motin (u_int)(now->frac & 0xffffffff)); 195a157e425SAlexander Motin done = 0; 196a157e425SAlexander Motin if (fake) { 197a157e425SAlexander Motin frame = NULL; 198a157e425SAlexander Motin usermode = 0; 199a157e425SAlexander Motin pc = 0; 200a157e425SAlexander Motin } else { 201a157e425SAlexander Motin frame = curthread->td_intr_frame; 202a157e425SAlexander Motin usermode = TRAPF_USERMODE(frame); 203a157e425SAlexander Motin pc = TRAPF_PC(frame); 204a157e425SAlexander Motin } 205dd7498aeSAndriy Gapon 206a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 207dd7498aeSAndriy Gapon 208bcfd016cSAlexander Motin runs = 0; 209a157e425SAlexander Motin while (bintime_cmp(now, &state->nexthard, >=)) { 210c0722d20SAlexander Motin bintime_addx(&state->nexthard, hardperiod.frac); 211a157e425SAlexander Motin runs++; 21243fe7d45SAlexander Motin } 213c0722d20SAlexander Motin if (runs) { 214fd053faeSAlexander Motin if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 && 215fd053faeSAlexander Motin bintime_cmp(&state->nexthard, &nexthard, >)) 216fd053faeSAlexander Motin nexthard = state->nexthard; 217c0722d20SAlexander Motin if (fake < 2) { 218bcfd016cSAlexander Motin hardclock_cnt(runs, usermode); 219a157e425SAlexander Motin done = 1; 22043fe7d45SAlexander Motin } 221c0722d20SAlexander Motin } 222bcfd016cSAlexander Motin runs = 0; 223a157e425SAlexander Motin while (bintime_cmp(now, &state->nextstat, >=)) { 224c0722d20SAlexander Motin bintime_addx(&state->nextstat, statperiod.frac); 225bcfd016cSAlexander Motin runs++; 226bcfd016cSAlexander Motin } 227bcfd016cSAlexander Motin if (runs && fake < 2) { 228bcfd016cSAlexander Motin statclock_cnt(runs, usermode); 229a157e425SAlexander Motin done = 1; 23043fe7d45SAlexander Motin } 231a157e425SAlexander Motin if (profiling) { 232bcfd016cSAlexander Motin runs = 0; 233a157e425SAlexander Motin while (bintime_cmp(now, &state->nextprof, >=)) { 234c0722d20SAlexander Motin bintime_addx(&state->nextprof, profperiod.frac); 235bcfd016cSAlexander Motin runs++; 236bcfd016cSAlexander Motin } 237bcfd016cSAlexander Motin if (runs && !fake) { 238bcfd016cSAlexander Motin profclock_cnt(runs, usermode, pc); 239a157e425SAlexander Motin done = 1; 24043fe7d45SAlexander Motin } 241a157e425SAlexander Motin } else 242a157e425SAlexander Motin state->nextprof = state->nextstat; 243dd7498aeSAndriy Gapon 244dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 245dd7498aeSAndriy Gapon if (fake == 0 && cyclic_clock_func != NULL && 246dd7498aeSAndriy Gapon state->nextcyc.sec != -1 && 247dd7498aeSAndriy Gapon bintime_cmp(now, &state->nextcyc, >=)) { 248dd7498aeSAndriy Gapon state->nextcyc.sec = -1; 249dd7498aeSAndriy Gapon (*cyclic_clock_func)(frame); 250dd7498aeSAndriy Gapon } 251dd7498aeSAndriy Gapon #endif 252dd7498aeSAndriy Gapon 253a157e425SAlexander Motin getnextcpuevent(&t, 0); 254c70410e6SAlexander Motin if (fake == 2) { 255c70410e6SAlexander Motin state->nextevent = t; 256c70410e6SAlexander Motin return (done); 257c70410e6SAlexander Motin } 258a157e425SAlexander Motin ET_HW_LOCK(state); 259a157e425SAlexander Motin if (!busy) { 260a157e425SAlexander Motin state->idle = 0; 261a157e425SAlexander Motin state->nextevent = t; 262a157e425SAlexander Motin loadtimer(now, 0); 26343fe7d45SAlexander Motin } 264a157e425SAlexander Motin ET_HW_UNLOCK(state); 265a157e425SAlexander Motin return (done); 26643fe7d45SAlexander Motin } 26743fe7d45SAlexander Motin 26843fe7d45SAlexander Motin /* 269a157e425SAlexander Motin * Schedule binuptime of the next event on current CPU. 27043fe7d45SAlexander Motin */ 27143fe7d45SAlexander Motin static void 272a157e425SAlexander Motin getnextcpuevent(struct bintime *event, int idle) 27343fe7d45SAlexander Motin { 274a157e425SAlexander Motin struct bintime tmp; 275a157e425SAlexander Motin struct pcpu_state *state; 276a157e425SAlexander Motin int skip; 27743fe7d45SAlexander Motin 278a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 279fd053faeSAlexander Motin /* Handle hardclock() events. */ 280a157e425SAlexander Motin *event = state->nexthard; 281fd053faeSAlexander Motin if (idle || (!activetick && !profiling && 282fd053faeSAlexander Motin (timer->et_flags & ET_FLAGS_PERCPU) == 0)) { 283fd053faeSAlexander Motin skip = idle ? 4 : (stathz / 2); 2840e189873SAlexander Motin if (curcpu == CPU_FIRST() && tc_min_ticktock_freq > skip) 2850e189873SAlexander Motin skip = tc_min_ticktock_freq; 2860e189873SAlexander Motin skip = callout_tickstofirst(hz / skip) - 1; 287a157e425SAlexander Motin CTR2(KTR_SPARE2, "skip at %d: %d", curcpu, skip); 288a157e425SAlexander Motin tmp = hardperiod; 289a157e425SAlexander Motin bintime_mul(&tmp, skip); 290a157e425SAlexander Motin bintime_add(event, &tmp); 291fd053faeSAlexander Motin } 292fd053faeSAlexander Motin if (!idle) { /* If CPU is active - handle other types of events. */ 293a157e425SAlexander Motin if (bintime_cmp(event, &state->nextstat, >)) 294a157e425SAlexander Motin *event = state->nextstat; 295dd7498aeSAndriy Gapon if (profiling && bintime_cmp(event, &state->nextprof, >)) 296a157e425SAlexander Motin *event = state->nextprof; 29743fe7d45SAlexander Motin } 298dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 299dd7498aeSAndriy Gapon if (state->nextcyc.sec != -1 && bintime_cmp(event, &state->nextcyc, >)) 300dd7498aeSAndriy Gapon *event = state->nextcyc; 301dd7498aeSAndriy Gapon #endif 30243fe7d45SAlexander Motin } 303a157e425SAlexander Motin 304a157e425SAlexander Motin /* 305a157e425SAlexander Motin * Schedule binuptime of the next event on all CPUs. 306a157e425SAlexander Motin */ 307a157e425SAlexander Motin static void 308a157e425SAlexander Motin getnextevent(struct bintime *event) 309a157e425SAlexander Motin { 310a157e425SAlexander Motin struct pcpu_state *state; 311a157e425SAlexander Motin #ifdef SMP 312a157e425SAlexander Motin int cpu; 313a157e425SAlexander Motin #endif 314fd053faeSAlexander Motin int c, nonidle; 315a157e425SAlexander Motin 316a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 317a157e425SAlexander Motin *event = state->nextevent; 318a157e425SAlexander Motin c = curcpu; 319fd053faeSAlexander Motin nonidle = !state->idle; 320a157e425SAlexander Motin if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) { 321fd053faeSAlexander Motin #ifdef SMP 3222d7d1642SGrzegorz Bernacki if (smp_started) { 323a157e425SAlexander Motin CPU_FOREACH(cpu) { 324a157e425SAlexander Motin if (curcpu == cpu) 325a157e425SAlexander Motin continue; 326a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 327fd053faeSAlexander Motin nonidle += !state->idle; 328a157e425SAlexander Motin if (bintime_cmp(event, &state->nextevent, >)) { 329a157e425SAlexander Motin *event = state->nextevent; 330a157e425SAlexander Motin c = cpu; 33143fe7d45SAlexander Motin } 33243fe7d45SAlexander Motin } 3332d7d1642SGrzegorz Bernacki } 334a157e425SAlexander Motin #endif 335fd053faeSAlexander Motin if (nonidle != 0 && bintime_cmp(event, &nexthard, >)) 336fd053faeSAlexander Motin *event = nexthard; 337fd053faeSAlexander Motin } 338a157e425SAlexander Motin CTR5(KTR_SPARE2, "next at %d: next %d.%08x%08x by %d", 3399b71c63aSAlexander Motin curcpu, event->sec, (u_int)(event->frac >> 32), 3409b71c63aSAlexander Motin (u_int)(event->frac & 0xffffffff), c); 341a157e425SAlexander Motin } 342a157e425SAlexander Motin 343a157e425SAlexander Motin /* Hardware timer callback function. */ 344a157e425SAlexander Motin static void 345a157e425SAlexander Motin timercb(struct eventtimer *et, void *arg) 346a157e425SAlexander Motin { 347a157e425SAlexander Motin struct bintime now; 348a157e425SAlexander Motin struct bintime *next; 349a157e425SAlexander Motin struct pcpu_state *state; 350a157e425SAlexander Motin #ifdef SMP 351a157e425SAlexander Motin int cpu, bcast; 352a157e425SAlexander Motin #endif 353a157e425SAlexander Motin 354a157e425SAlexander Motin /* Do not touch anything if somebody reconfiguring timers. */ 355a157e425SAlexander Motin if (busy) 356a157e425SAlexander Motin return; 357a157e425SAlexander Motin /* Update present and next tick times. */ 358a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 359a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_PERCPU) { 360a157e425SAlexander Motin next = &state->nexttick; 361a157e425SAlexander Motin } else 362a157e425SAlexander Motin next = &nexttick; 36320389430SAlexander Motin binuptime(&now); 364a157e425SAlexander Motin if (periodic) { 36520389430SAlexander Motin *next = now; 366c0722d20SAlexander Motin bintime_addx(next, timerperiod.frac); /* Next tick in 1 period. */ 36720389430SAlexander Motin } else 368a157e425SAlexander Motin next->sec = -1; /* Next tick is not scheduled yet. */ 369a157e425SAlexander Motin state->now = now; 370a157e425SAlexander Motin CTR4(KTR_SPARE2, "intr at %d: now %d.%08x%08x", 3719b71c63aSAlexander Motin curcpu, (int)(now.sec), (u_int)(now.frac >> 32), 3729b71c63aSAlexander Motin (u_int)(now.frac & 0xffffffff)); 373a157e425SAlexander Motin 374a157e425SAlexander Motin #ifdef SMP 375a157e425SAlexander Motin /* Prepare broadcasting to other CPUs for non-per-CPU timers. */ 376a157e425SAlexander Motin bcast = 0; 377a157e425SAlexander Motin if ((et->et_flags & ET_FLAGS_PERCPU) == 0 && smp_started) { 378a157e425SAlexander Motin CPU_FOREACH(cpu) { 379a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 380a157e425SAlexander Motin ET_HW_LOCK(state); 381a157e425SAlexander Motin state->now = now; 382a157e425SAlexander Motin if (bintime_cmp(&now, &state->nextevent, >=)) { 383a157e425SAlexander Motin state->nextevent.sec++; 3848e860de4SAlexander Motin if (curcpu != cpu) { 385a157e425SAlexander Motin state->ipi = 1; 386a157e425SAlexander Motin bcast = 1; 387a157e425SAlexander Motin } 3888e860de4SAlexander Motin } 389a157e425SAlexander Motin ET_HW_UNLOCK(state); 390a157e425SAlexander Motin } 391a157e425SAlexander Motin } 392a157e425SAlexander Motin #endif 393a157e425SAlexander Motin 394a157e425SAlexander Motin /* Handle events for this time on this CPU. */ 395a157e425SAlexander Motin handleevents(&now, 0); 396a157e425SAlexander Motin 397a157e425SAlexander Motin #ifdef SMP 398a157e425SAlexander Motin /* Broadcast interrupt to other CPUs for non-per-CPU timers. */ 399a157e425SAlexander Motin if (bcast) { 400a157e425SAlexander Motin CPU_FOREACH(cpu) { 401a157e425SAlexander Motin if (curcpu == cpu) 402a157e425SAlexander Motin continue; 403a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 404a157e425SAlexander Motin if (state->ipi) { 405a157e425SAlexander Motin state->ipi = 0; 406a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 407a157e425SAlexander Motin } 408a157e425SAlexander Motin } 409a157e425SAlexander Motin } 410a157e425SAlexander Motin #endif 411a157e425SAlexander Motin } 412a157e425SAlexander Motin 413a157e425SAlexander Motin /* 414a157e425SAlexander Motin * Load new value into hardware timer. 415a157e425SAlexander Motin */ 416a157e425SAlexander Motin static void 417a157e425SAlexander Motin loadtimer(struct bintime *now, int start) 418a157e425SAlexander Motin { 419a157e425SAlexander Motin struct pcpu_state *state; 420a157e425SAlexander Motin struct bintime new; 421a157e425SAlexander Motin struct bintime *next; 422a157e425SAlexander Motin uint64_t tmp; 423a157e425SAlexander Motin int eq; 424a157e425SAlexander Motin 425c70410e6SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) { 426c70410e6SAlexander Motin state = DPCPU_PTR(timerstate); 427c70410e6SAlexander Motin next = &state->nexttick; 428c70410e6SAlexander Motin } else 429c70410e6SAlexander Motin next = &nexttick; 430a157e425SAlexander Motin if (periodic) { 431a157e425SAlexander Motin if (start) { 432a157e425SAlexander Motin /* 433a157e425SAlexander Motin * Try to start all periodic timers aligned 434a157e425SAlexander Motin * to period to make events synchronous. 435a157e425SAlexander Motin */ 436a157e425SAlexander Motin tmp = ((uint64_t)now->sec << 36) + (now->frac >> 28); 437a157e425SAlexander Motin tmp = (tmp % (timerperiod.frac >> 28)) << 28; 438c70410e6SAlexander Motin new.sec = 0; 439c70410e6SAlexander Motin new.frac = timerperiod.frac - tmp; 440c70410e6SAlexander Motin if (new.frac < tmp) /* Left less then passed. */ 441c0722d20SAlexander Motin bintime_addx(&new, timerperiod.frac); 442a157e425SAlexander Motin CTR5(KTR_SPARE2, "load p at %d: now %d.%08x first in %d.%08x", 4439b71c63aSAlexander Motin curcpu, now->sec, (u_int)(now->frac >> 32), 4449b71c63aSAlexander Motin new.sec, (u_int)(new.frac >> 32)); 445c70410e6SAlexander Motin *next = new; 446c70410e6SAlexander Motin bintime_add(next, now); 447*fdc5dd2dSAlexander Motin et_start(timer, bttosbt(new), bttosbt(timerperiod)); 448a157e425SAlexander Motin } 449a157e425SAlexander Motin } else { 450a157e425SAlexander Motin getnextevent(&new); 451a157e425SAlexander Motin eq = bintime_cmp(&new, next, ==); 452a157e425SAlexander Motin CTR5(KTR_SPARE2, "load at %d: next %d.%08x%08x eq %d", 4539b71c63aSAlexander Motin curcpu, new.sec, (u_int)(new.frac >> 32), 4549b71c63aSAlexander Motin (u_int)(new.frac & 0xffffffff), 455a157e425SAlexander Motin eq); 456a157e425SAlexander Motin if (!eq) { 457a157e425SAlexander Motin *next = new; 458a157e425SAlexander Motin bintime_sub(&new, now); 459*fdc5dd2dSAlexander Motin et_start(timer, bttosbt(new), 0); 460a157e425SAlexander Motin } 461a157e425SAlexander Motin } 462a157e425SAlexander Motin } 463a157e425SAlexander Motin 464a157e425SAlexander Motin /* 465a157e425SAlexander Motin * Prepare event timer parameters after configuration changes. 466a157e425SAlexander Motin */ 467a157e425SAlexander Motin static void 468a157e425SAlexander Motin setuptimer(void) 469a157e425SAlexander Motin { 470a157e425SAlexander Motin int freq; 471a157e425SAlexander Motin 472a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 473a157e425SAlexander Motin periodic = 0; 474a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 475a157e425SAlexander Motin periodic = 1; 476dd9595e7SAlexander Motin singlemul = MIN(MAX(singlemul, 1), 20); 477a157e425SAlexander Motin freq = hz * singlemul; 478a157e425SAlexander Motin while (freq < (profiling ? profhz : stathz)) 479a157e425SAlexander Motin freq += hz; 480a157e425SAlexander Motin freq = round_freq(timer, freq); 481a157e425SAlexander Motin FREQ2BT(freq, &timerperiod); 482a157e425SAlexander Motin } 48343fe7d45SAlexander Motin 48443fe7d45SAlexander Motin /* 48543fe7d45SAlexander Motin * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler. 48643fe7d45SAlexander Motin */ 487a157e425SAlexander Motin static int 488a157e425SAlexander Motin doconfigtimer(void) 48943fe7d45SAlexander Motin { 490a157e425SAlexander Motin struct bintime now; 491a157e425SAlexander Motin struct pcpu_state *state; 49243fe7d45SAlexander Motin 493a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 494a157e425SAlexander Motin switch (atomic_load_acq_int(&state->action)) { 495a157e425SAlexander Motin case 1: 496a157e425SAlexander Motin binuptime(&now); 497a157e425SAlexander Motin ET_HW_LOCK(state); 498a157e425SAlexander Motin loadtimer(&now, 1); 499a157e425SAlexander Motin ET_HW_UNLOCK(state); 500a157e425SAlexander Motin state->handle = 0; 501a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 502a157e425SAlexander Motin return (1); 503a157e425SAlexander Motin case 2: 504a157e425SAlexander Motin ET_HW_LOCK(state); 505a157e425SAlexander Motin et_stop(timer); 506a157e425SAlexander Motin ET_HW_UNLOCK(state); 507a157e425SAlexander Motin state->handle = 0; 508a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 509a157e425SAlexander Motin return (1); 510a157e425SAlexander Motin } 511a157e425SAlexander Motin if (atomic_readandclear_int(&state->handle) && !busy) { 512a157e425SAlexander Motin binuptime(&now); 513a157e425SAlexander Motin handleevents(&now, 0); 51443fe7d45SAlexander Motin return (1); 51543fe7d45SAlexander Motin } 51643fe7d45SAlexander Motin return (0); 51743fe7d45SAlexander Motin } 51843fe7d45SAlexander Motin 51943fe7d45SAlexander Motin /* 52043fe7d45SAlexander Motin * Reconfigure specified timer. 52143fe7d45SAlexander Motin * For per-CPU timers use IPI to make other CPUs to reconfigure. 52243fe7d45SAlexander Motin */ 52343fe7d45SAlexander Motin static void 524a157e425SAlexander Motin configtimer(int start) 52543fe7d45SAlexander Motin { 526a157e425SAlexander Motin struct bintime now, next; 527a157e425SAlexander Motin struct pcpu_state *state; 52843fe7d45SAlexander Motin int cpu; 52943fe7d45SAlexander Motin 530a157e425SAlexander Motin if (start) { 531a157e425SAlexander Motin setuptimer(); 532a157e425SAlexander Motin binuptime(&now); 533a157e425SAlexander Motin } 53443fe7d45SAlexander Motin critical_enter(); 535a157e425SAlexander Motin ET_HW_LOCK(DPCPU_PTR(timerstate)); 536a157e425SAlexander Motin if (start) { 537a157e425SAlexander Motin /* Initialize time machine parameters. */ 538a157e425SAlexander Motin next = now; 539c0722d20SAlexander Motin bintime_addx(&next, timerperiod.frac); 540a157e425SAlexander Motin if (periodic) 541a157e425SAlexander Motin nexttick = next; 54243fe7d45SAlexander Motin else 543a157e425SAlexander Motin nexttick.sec = -1; 544a157e425SAlexander Motin CPU_FOREACH(cpu) { 545a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 546a157e425SAlexander Motin state->now = now; 547a157e425SAlexander Motin state->nextevent = next; 548a157e425SAlexander Motin if (periodic) 549a157e425SAlexander Motin state->nexttick = next; 550a157e425SAlexander Motin else 551a157e425SAlexander Motin state->nexttick.sec = -1; 552a157e425SAlexander Motin state->nexthard = next; 553a157e425SAlexander Motin state->nextstat = next; 554a157e425SAlexander Motin state->nextprof = next; 555a157e425SAlexander Motin hardclock_sync(cpu); 556a157e425SAlexander Motin } 557a157e425SAlexander Motin busy = 0; 558a157e425SAlexander Motin /* Start global timer or per-CPU timer of this CPU. */ 559a157e425SAlexander Motin loadtimer(&now, 1); 560a157e425SAlexander Motin } else { 561a157e425SAlexander Motin busy = 1; 562a157e425SAlexander Motin /* Stop global timer or per-CPU timer of this CPU. */ 563a157e425SAlexander Motin et_stop(timer); 564a157e425SAlexander Motin } 565a157e425SAlexander Motin ET_HW_UNLOCK(DPCPU_PTR(timerstate)); 56643fe7d45SAlexander Motin #ifdef SMP 567a157e425SAlexander Motin /* If timer is global or there is no other CPUs yet - we are done. */ 568a157e425SAlexander Motin if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) { 56943fe7d45SAlexander Motin critical_exit(); 57043fe7d45SAlexander Motin return; 57143fe7d45SAlexander Motin } 57243fe7d45SAlexander Motin /* Set reconfigure flags for other CPUs. */ 57343fe7d45SAlexander Motin CPU_FOREACH(cpu) { 574a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 575a157e425SAlexander Motin atomic_store_rel_int(&state->action, 576a157e425SAlexander Motin (cpu == curcpu) ? 0 : ( start ? 1 : 2)); 57743fe7d45SAlexander Motin } 578a157e425SAlexander Motin /* Broadcast reconfigure IPI. */ 579a157e425SAlexander Motin ipi_all_but_self(IPI_HARDCLOCK); 58043fe7d45SAlexander Motin /* Wait for reconfiguration completed. */ 58143fe7d45SAlexander Motin restart: 58243fe7d45SAlexander Motin cpu_spinwait(); 58343fe7d45SAlexander Motin CPU_FOREACH(cpu) { 58443fe7d45SAlexander Motin if (cpu == curcpu) 58543fe7d45SAlexander Motin continue; 586a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 587a157e425SAlexander Motin if (atomic_load_acq_int(&state->action)) 58843fe7d45SAlexander Motin goto restart; 58943fe7d45SAlexander Motin } 59043fe7d45SAlexander Motin #endif 591a157e425SAlexander Motin critical_exit(); 59243fe7d45SAlexander Motin } 59343fe7d45SAlexander Motin 594a157e425SAlexander Motin /* 595a157e425SAlexander Motin * Calculate nearest frequency supported by hardware timer. 596a157e425SAlexander Motin */ 59751636352SAlexander Motin static int 59851636352SAlexander Motin round_freq(struct eventtimer *et, int freq) 59951636352SAlexander Motin { 60051636352SAlexander Motin uint64_t div; 60151636352SAlexander Motin 60251636352SAlexander Motin if (et->et_frequency != 0) { 603599cf0f1SAlexander Motin div = lmax((et->et_frequency + freq / 2) / freq, 1); 60451636352SAlexander Motin if (et->et_flags & ET_FLAGS_POW2DIV) 60551636352SAlexander Motin div = 1 << (flsl(div + div / 2) - 1); 60651636352SAlexander Motin freq = (et->et_frequency + div / 2) / div; 60751636352SAlexander Motin } 608*fdc5dd2dSAlexander Motin if (et->et_min_period > SBT_1S) 609803a9b3eSAlexander Motin panic("Event timer \"%s\" doesn't support sub-second periods!", 610803a9b3eSAlexander Motin et->et_name); 611*fdc5dd2dSAlexander Motin else if (et->et_min_period != 0) 612*fdc5dd2dSAlexander Motin freq = min(freq, SBT2FREQ(et->et_min_period)); 613*fdc5dd2dSAlexander Motin if (et->et_max_period < SBT_1S && et->et_max_period != 0) 614*fdc5dd2dSAlexander Motin freq = max(freq, SBT2FREQ(et->et_max_period)); 61551636352SAlexander Motin return (freq); 61651636352SAlexander Motin } 61751636352SAlexander Motin 61843fe7d45SAlexander Motin /* 619a157e425SAlexander Motin * Configure and start event timers (BSP part). 62043fe7d45SAlexander Motin */ 62143fe7d45SAlexander Motin void 62243fe7d45SAlexander Motin cpu_initclocks_bsp(void) 62343fe7d45SAlexander Motin { 624a157e425SAlexander Motin struct pcpu_state *state; 625a157e425SAlexander Motin int base, div, cpu; 62643fe7d45SAlexander Motin 627a157e425SAlexander Motin mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 628a157e425SAlexander Motin CPU_FOREACH(cpu) { 629a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 630a157e425SAlexander Motin mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 631dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 632dd7498aeSAndriy Gapon state->nextcyc.sec = -1; 633dd7498aeSAndriy Gapon #endif 634a157e425SAlexander Motin } 635a157e425SAlexander Motin #ifdef SMP 636a157e425SAlexander Motin callout_new_inserted = cpu_new_callout; 637a157e425SAlexander Motin #endif 638afe41f2dSAlexander Motin periodic = want_periodic; 639a157e425SAlexander Motin /* Grab requested timer or the best of present. */ 640a157e425SAlexander Motin if (timername[0]) 641a157e425SAlexander Motin timer = et_find(timername, 0, 0); 642a157e425SAlexander Motin if (timer == NULL && periodic) { 643a157e425SAlexander Motin timer = et_find(NULL, 64443fe7d45SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 645a157e425SAlexander Motin } 646a157e425SAlexander Motin if (timer == NULL) { 647a157e425SAlexander Motin timer = et_find(NULL, 648a157e425SAlexander Motin ET_FLAGS_ONESHOT, ET_FLAGS_ONESHOT); 649a157e425SAlexander Motin } 650a157e425SAlexander Motin if (timer == NULL && !periodic) { 651a157e425SAlexander Motin timer = et_find(NULL, 652a157e425SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 653a157e425SAlexander Motin } 654a157e425SAlexander Motin if (timer == NULL) 655a157e425SAlexander Motin panic("No usable event timer found!"); 656a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 657a157e425SAlexander Motin 658a157e425SAlexander Motin /* Adapt to timer capabilities. */ 659a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 660a157e425SAlexander Motin periodic = 0; 661a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 662a157e425SAlexander Motin periodic = 1; 663a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 664a157e425SAlexander Motin cpu_disable_deep_sleep++; 665a157e425SAlexander Motin 66643fe7d45SAlexander Motin /* 66743fe7d45SAlexander Motin * We honor the requested 'hz' value. 66843fe7d45SAlexander Motin * We want to run stathz in the neighborhood of 128hz. 66943fe7d45SAlexander Motin * We would like profhz to run as often as possible. 67043fe7d45SAlexander Motin */ 671dd9595e7SAlexander Motin if (singlemul <= 0 || singlemul > 20) { 67243fe7d45SAlexander Motin if (hz >= 1500 || (hz % 128) == 0) 67343fe7d45SAlexander Motin singlemul = 1; 67443fe7d45SAlexander Motin else if (hz >= 750) 67543fe7d45SAlexander Motin singlemul = 2; 67643fe7d45SAlexander Motin else 67743fe7d45SAlexander Motin singlemul = 4; 67843fe7d45SAlexander Motin } 679a157e425SAlexander Motin if (periodic) { 680a157e425SAlexander Motin base = round_freq(timer, hz * singlemul); 68151636352SAlexander Motin singlemul = max((base + hz / 2) / hz, 1); 68251636352SAlexander Motin hz = (base + singlemul / 2) / singlemul; 68351636352SAlexander Motin if (base <= 128) 68443fe7d45SAlexander Motin stathz = base; 68543fe7d45SAlexander Motin else { 68643fe7d45SAlexander Motin div = base / 128; 68751636352SAlexander Motin if (div >= singlemul && (div % singlemul) == 0) 68843fe7d45SAlexander Motin div++; 68943fe7d45SAlexander Motin stathz = base / div; 69043fe7d45SAlexander Motin } 69143fe7d45SAlexander Motin profhz = stathz; 69251636352SAlexander Motin while ((profhz + stathz) <= 128 * 64) 69343fe7d45SAlexander Motin profhz += stathz; 694a157e425SAlexander Motin profhz = round_freq(timer, profhz); 69543fe7d45SAlexander Motin } else { 696a157e425SAlexander Motin hz = round_freq(timer, hz); 697a157e425SAlexander Motin stathz = round_freq(timer, 127); 698a157e425SAlexander Motin profhz = round_freq(timer, stathz * 64); 69943fe7d45SAlexander Motin } 700599cf0f1SAlexander Motin tick = 1000000 / hz; 701a157e425SAlexander Motin FREQ2BT(hz, &hardperiod); 702a157e425SAlexander Motin FREQ2BT(stathz, &statperiod); 703a157e425SAlexander Motin FREQ2BT(profhz, &profperiod); 70443fe7d45SAlexander Motin ET_LOCK(); 705a157e425SAlexander Motin configtimer(1); 70643fe7d45SAlexander Motin ET_UNLOCK(); 70743fe7d45SAlexander Motin } 70843fe7d45SAlexander Motin 709a157e425SAlexander Motin /* 710a157e425SAlexander Motin * Start per-CPU event timers on APs. 711a157e425SAlexander Motin */ 71243fe7d45SAlexander Motin void 71343fe7d45SAlexander Motin cpu_initclocks_ap(void) 71443fe7d45SAlexander Motin { 715a157e425SAlexander Motin struct bintime now; 716a157e425SAlexander Motin struct pcpu_state *state; 71743fe7d45SAlexander Motin 718a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 719a157e425SAlexander Motin binuptime(&now); 720a157e425SAlexander Motin ET_HW_LOCK(state); 721c70410e6SAlexander Motin state->now = now; 722c70410e6SAlexander Motin hardclock_sync(curcpu); 723c70410e6SAlexander Motin handleevents(&state->now, 2); 724c70410e6SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) 725a157e425SAlexander Motin loadtimer(&now, 1); 726a157e425SAlexander Motin ET_HW_UNLOCK(state); 72743fe7d45SAlexander Motin } 72843fe7d45SAlexander Motin 729a157e425SAlexander Motin /* 730a157e425SAlexander Motin * Switch to profiling clock rates. 731a157e425SAlexander Motin */ 73243fe7d45SAlexander Motin void 73343fe7d45SAlexander Motin cpu_startprofclock(void) 73443fe7d45SAlexander Motin { 73543fe7d45SAlexander Motin 73643fe7d45SAlexander Motin ET_LOCK(); 7371af19ee4SAlexander Motin if (profiling == 0) { 738a157e425SAlexander Motin if (periodic) { 739a157e425SAlexander Motin configtimer(0); 740a157e425SAlexander Motin profiling = 1; 741a157e425SAlexander Motin configtimer(1); 742a157e425SAlexander Motin } else 743a157e425SAlexander Motin profiling = 1; 7441af19ee4SAlexander Motin } else 7451af19ee4SAlexander Motin profiling++; 74643fe7d45SAlexander Motin ET_UNLOCK(); 74743fe7d45SAlexander Motin } 74843fe7d45SAlexander Motin 749a157e425SAlexander Motin /* 750a157e425SAlexander Motin * Switch to regular clock rates. 751a157e425SAlexander Motin */ 75243fe7d45SAlexander Motin void 75343fe7d45SAlexander Motin cpu_stopprofclock(void) 75443fe7d45SAlexander Motin { 75543fe7d45SAlexander Motin 75643fe7d45SAlexander Motin ET_LOCK(); 7571af19ee4SAlexander Motin if (profiling == 1) { 758a157e425SAlexander Motin if (periodic) { 759a157e425SAlexander Motin configtimer(0); 760a157e425SAlexander Motin profiling = 0; 761a157e425SAlexander Motin configtimer(1); 762a157e425SAlexander Motin } else 763a157e425SAlexander Motin profiling = 0; 7641af19ee4SAlexander Motin } else 7651af19ee4SAlexander Motin profiling--; 76643fe7d45SAlexander Motin ET_UNLOCK(); 76743fe7d45SAlexander Motin } 76843fe7d45SAlexander Motin 769a157e425SAlexander Motin /* 770a157e425SAlexander Motin * Switch to idle mode (all ticks handled). 771a157e425SAlexander Motin */ 772acccf7d8SDavide Italiano sbintime_t 773a157e425SAlexander Motin cpu_idleclock(void) 774a157e425SAlexander Motin { 775a157e425SAlexander Motin struct bintime now, t; 776a157e425SAlexander Motin struct pcpu_state *state; 777a157e425SAlexander Motin 778a157e425SAlexander Motin if (idletick || busy || 7799dfc483cSAlexander Motin (periodic && (timer->et_flags & ET_FLAGS_PERCPU)) 7809dfc483cSAlexander Motin #ifdef DEVICE_POLLING 7819dfc483cSAlexander Motin || curcpu == CPU_FIRST() 7829dfc483cSAlexander Motin #endif 7839dfc483cSAlexander Motin ) 784acccf7d8SDavide Italiano return (-1); 785a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 786a157e425SAlexander Motin if (periodic) 787a157e425SAlexander Motin now = state->now; 788a157e425SAlexander Motin else 789a157e425SAlexander Motin binuptime(&now); 790a157e425SAlexander Motin CTR4(KTR_SPARE2, "idle at %d: now %d.%08x%08x", 7919b71c63aSAlexander Motin curcpu, now.sec, (u_int)(now.frac >> 32), 7929b71c63aSAlexander Motin (u_int)(now.frac & 0xffffffff)); 793a157e425SAlexander Motin getnextcpuevent(&t, 1); 794a157e425SAlexander Motin ET_HW_LOCK(state); 795a157e425SAlexander Motin state->idle = 1; 796a157e425SAlexander Motin state->nextevent = t; 797a157e425SAlexander Motin if (!periodic) 798a157e425SAlexander Motin loadtimer(&now, 0); 799a157e425SAlexander Motin ET_HW_UNLOCK(state); 800acccf7d8SDavide Italiano bintime_sub(&t, &now); 801acccf7d8SDavide Italiano return (MAX(bttosbt(t), 0)); 802a157e425SAlexander Motin } 803a157e425SAlexander Motin 804a157e425SAlexander Motin /* 805a157e425SAlexander Motin * Switch to active mode (skip empty ticks). 806a157e425SAlexander Motin */ 807a157e425SAlexander Motin void 808a157e425SAlexander Motin cpu_activeclock(void) 809a157e425SAlexander Motin { 810a157e425SAlexander Motin struct bintime now; 811a157e425SAlexander Motin struct pcpu_state *state; 812a157e425SAlexander Motin struct thread *td; 813a157e425SAlexander Motin 814a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 815a157e425SAlexander Motin if (state->idle == 0 || busy) 816a157e425SAlexander Motin return; 817a157e425SAlexander Motin if (periodic) 818a157e425SAlexander Motin now = state->now; 819a157e425SAlexander Motin else 820a157e425SAlexander Motin binuptime(&now); 821a157e425SAlexander Motin CTR4(KTR_SPARE2, "active at %d: now %d.%08x%08x", 8229b71c63aSAlexander Motin curcpu, now.sec, (u_int)(now.frac >> 32), 8239b71c63aSAlexander Motin (u_int)(now.frac & 0xffffffff)); 824a157e425SAlexander Motin spinlock_enter(); 825a157e425SAlexander Motin td = curthread; 826a157e425SAlexander Motin td->td_intr_nesting_level++; 827a157e425SAlexander Motin handleevents(&now, 1); 828a157e425SAlexander Motin td->td_intr_nesting_level--; 829a157e425SAlexander Motin spinlock_exit(); 830a157e425SAlexander Motin } 831a157e425SAlexander Motin 832dd7498aeSAndriy Gapon #ifdef KDTRACE_HOOKS 833dd7498aeSAndriy Gapon void 834dd7498aeSAndriy Gapon clocksource_cyc_set(const struct bintime *t) 835dd7498aeSAndriy Gapon { 836dd7498aeSAndriy Gapon struct bintime now; 837dd7498aeSAndriy Gapon struct pcpu_state *state; 838dd7498aeSAndriy Gapon 839dd7498aeSAndriy Gapon state = DPCPU_PTR(timerstate); 840dd7498aeSAndriy Gapon if (periodic) 841dd7498aeSAndriy Gapon now = state->now; 842dd7498aeSAndriy Gapon else 843dd7498aeSAndriy Gapon binuptime(&now); 844dd7498aeSAndriy Gapon 845dd7498aeSAndriy Gapon CTR4(KTR_SPARE2, "set_cyc at %d: now %d.%08x%08x", 8469b71c63aSAlexander Motin curcpu, now.sec, (u_int)(now.frac >> 32), 8479b71c63aSAlexander Motin (u_int)(now.frac & 0xffffffff)); 848dd7498aeSAndriy Gapon CTR4(KTR_SPARE2, "set_cyc at %d: t %d.%08x%08x", 8499b71c63aSAlexander Motin curcpu, t->sec, (u_int)(t->frac >> 32), 8509b71c63aSAlexander Motin (u_int)(t->frac & 0xffffffff)); 851dd7498aeSAndriy Gapon 852dd7498aeSAndriy Gapon ET_HW_LOCK(state); 853dd7498aeSAndriy Gapon if (bintime_cmp(t, &state->nextcyc, ==)) { 854dd7498aeSAndriy Gapon ET_HW_UNLOCK(state); 855dd7498aeSAndriy Gapon return; 856dd7498aeSAndriy Gapon } 857dd7498aeSAndriy Gapon state->nextcyc = *t; 858dd7498aeSAndriy Gapon if (bintime_cmp(&state->nextcyc, &state->nextevent, >=)) { 859dd7498aeSAndriy Gapon ET_HW_UNLOCK(state); 860dd7498aeSAndriy Gapon return; 861dd7498aeSAndriy Gapon } 862dd7498aeSAndriy Gapon state->nextevent = state->nextcyc; 863dd7498aeSAndriy Gapon if (!periodic) 864dd7498aeSAndriy Gapon loadtimer(&now, 0); 865dd7498aeSAndriy Gapon ET_HW_UNLOCK(state); 866dd7498aeSAndriy Gapon } 867dd7498aeSAndriy Gapon #endif 868dd7498aeSAndriy Gapon 869a157e425SAlexander Motin #ifdef SMP 870a157e425SAlexander Motin static void 871a157e425SAlexander Motin cpu_new_callout(int cpu, int ticks) 872a157e425SAlexander Motin { 873a157e425SAlexander Motin struct bintime tmp; 874a157e425SAlexander Motin struct pcpu_state *state; 875a157e425SAlexander Motin 876a157e425SAlexander Motin CTR3(KTR_SPARE2, "new co at %d: on %d in %d", 877a157e425SAlexander Motin curcpu, cpu, ticks); 878a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 879a157e425SAlexander Motin ET_HW_LOCK(state); 880a157e425SAlexander Motin if (state->idle == 0 || busy) { 881a157e425SAlexander Motin ET_HW_UNLOCK(state); 882a157e425SAlexander Motin return; 883a157e425SAlexander Motin } 884a157e425SAlexander Motin /* 885a157e425SAlexander Motin * If timer is periodic - just update next event time for target CPU. 886bcb74c4cSAlexander Motin * If timer is global - there is chance it is already programmed. 887a157e425SAlexander Motin */ 888bcb74c4cSAlexander Motin if (periodic || (timer->et_flags & ET_FLAGS_PERCPU) == 0) { 889a157e425SAlexander Motin tmp = hardperiod; 890a157e425SAlexander Motin bintime_mul(&tmp, ticks - 1); 89155c71d63SAlexander Motin bintime_add(&tmp, &state->nexthard); 89255c71d63SAlexander Motin if (bintime_cmp(&tmp, &state->nextevent, <)) 89355c71d63SAlexander Motin state->nextevent = tmp; 894bcb74c4cSAlexander Motin if (periodic || 895bcb74c4cSAlexander Motin bintime_cmp(&state->nextevent, &nexttick, >=)) { 896a157e425SAlexander Motin ET_HW_UNLOCK(state); 897a157e425SAlexander Motin return; 898a157e425SAlexander Motin } 899bcb74c4cSAlexander Motin } 900a157e425SAlexander Motin /* 901a157e425SAlexander Motin * Otherwise we have to wake that CPU up, as we can't get present 902a157e425SAlexander Motin * bintime to reprogram global timer from here. If timer is per-CPU, 903a157e425SAlexander Motin * we by definition can't do it from here. 904a157e425SAlexander Motin */ 905a157e425SAlexander Motin ET_HW_UNLOCK(state); 906a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) { 907a157e425SAlexander Motin state->handle = 1; 908a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 909a157e425SAlexander Motin } else { 910a157e425SAlexander Motin if (!cpu_idle_wakeup(cpu)) 911a157e425SAlexander Motin ipi_cpu(cpu, IPI_AST); 912a157e425SAlexander Motin } 913a157e425SAlexander Motin } 914a157e425SAlexander Motin #endif 915a157e425SAlexander Motin 916a157e425SAlexander Motin /* 917a157e425SAlexander Motin * Report or change the active event timers hardware. 918a157e425SAlexander Motin */ 91943fe7d45SAlexander Motin static int 920a157e425SAlexander Motin sysctl_kern_eventtimer_timer(SYSCTL_HANDLER_ARGS) 92143fe7d45SAlexander Motin { 92243fe7d45SAlexander Motin char buf[32]; 92343fe7d45SAlexander Motin struct eventtimer *et; 92443fe7d45SAlexander Motin int error; 92543fe7d45SAlexander Motin 92643fe7d45SAlexander Motin ET_LOCK(); 927a157e425SAlexander Motin et = timer; 92843fe7d45SAlexander Motin snprintf(buf, sizeof(buf), "%s", et->et_name); 92943fe7d45SAlexander Motin ET_UNLOCK(); 93043fe7d45SAlexander Motin error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 93143fe7d45SAlexander Motin ET_LOCK(); 932a157e425SAlexander Motin et = timer; 93343fe7d45SAlexander Motin if (error != 0 || req->newptr == NULL || 934a157e425SAlexander Motin strcasecmp(buf, et->et_name) == 0) { 93543fe7d45SAlexander Motin ET_UNLOCK(); 93643fe7d45SAlexander Motin return (error); 93743fe7d45SAlexander Motin } 938a157e425SAlexander Motin et = et_find(buf, 0, 0); 93943fe7d45SAlexander Motin if (et == NULL) { 94043fe7d45SAlexander Motin ET_UNLOCK(); 94143fe7d45SAlexander Motin return (ENOENT); 94243fe7d45SAlexander Motin } 94343fe7d45SAlexander Motin configtimer(0); 944a157e425SAlexander Motin et_free(timer); 945a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_C3STOP) 946a157e425SAlexander Motin cpu_disable_deep_sleep++; 947a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 948a157e425SAlexander Motin cpu_disable_deep_sleep--; 949afe41f2dSAlexander Motin periodic = want_periodic; 950a157e425SAlexander Motin timer = et; 951a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 95243fe7d45SAlexander Motin configtimer(1); 95343fe7d45SAlexander Motin ET_UNLOCK(); 95443fe7d45SAlexander Motin return (error); 95543fe7d45SAlexander Motin } 956a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer, 95743fe7d45SAlexander Motin CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 958dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_timer, "A", "Chosen event timer"); 959a157e425SAlexander Motin 960a157e425SAlexander Motin /* 961a157e425SAlexander Motin * Report or change the active event timer periodicity. 962a157e425SAlexander Motin */ 963a157e425SAlexander Motin static int 964a157e425SAlexander Motin sysctl_kern_eventtimer_periodic(SYSCTL_HANDLER_ARGS) 965a157e425SAlexander Motin { 966a157e425SAlexander Motin int error, val; 967a157e425SAlexander Motin 968a157e425SAlexander Motin val = periodic; 969a157e425SAlexander Motin error = sysctl_handle_int(oidp, &val, 0, req); 970a157e425SAlexander Motin if (error != 0 || req->newptr == NULL) 971a157e425SAlexander Motin return (error); 972a157e425SAlexander Motin ET_LOCK(); 973a157e425SAlexander Motin configtimer(0); 974afe41f2dSAlexander Motin periodic = want_periodic = val; 975a157e425SAlexander Motin configtimer(1); 976a157e425SAlexander Motin ET_UNLOCK(); 977a157e425SAlexander Motin return (error); 978a157e425SAlexander Motin } 979a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, periodic, 980a157e425SAlexander Motin CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 981dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_periodic, "I", "Enable event timer periodic mode"); 982