143fe7d45SAlexander Motin /*- 243fe7d45SAlexander Motin * Copyright (c) 2010 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 3443fe7d45SAlexander Motin /* XEN has own timer routines now. */ 3543fe7d45SAlexander Motin #ifndef XEN 3643fe7d45SAlexander Motin 379dfc483cSAlexander Motin #include "opt_device_polling.h" 3843fe7d45SAlexander Motin #include "opt_kdtrace.h" 3943fe7d45SAlexander Motin 4043fe7d45SAlexander Motin #include <sys/param.h> 4143fe7d45SAlexander Motin #include <sys/systm.h> 4243fe7d45SAlexander Motin #include <sys/bus.h> 4343fe7d45SAlexander Motin #include <sys/lock.h> 4443fe7d45SAlexander Motin #include <sys/kdb.h> 45a157e425SAlexander Motin #include <sys/ktr.h> 4643fe7d45SAlexander Motin #include <sys/mutex.h> 4743fe7d45SAlexander Motin #include <sys/proc.h> 4843fe7d45SAlexander Motin #include <sys/kernel.h> 4943fe7d45SAlexander Motin #include <sys/sched.h> 5043fe7d45SAlexander Motin #include <sys/smp.h> 5143fe7d45SAlexander Motin #include <sys/sysctl.h> 5243fe7d45SAlexander Motin #include <sys/timeet.h> 530e189873SAlexander Motin #include <sys/timetc.h> 5443fe7d45SAlexander Motin 5543fe7d45SAlexander Motin #include <machine/atomic.h> 5643fe7d45SAlexander Motin #include <machine/clock.h> 5743fe7d45SAlexander Motin #include <machine/cpu.h> 5843fe7d45SAlexander Motin #include <machine/smp.h> 5943fe7d45SAlexander Motin 6043fe7d45SAlexander Motin #ifdef KDTRACE_HOOKS 6143fe7d45SAlexander Motin #include <sys/dtrace_bsd.h> 6243fe7d45SAlexander Motin cyclic_clock_func_t cyclic_clock_func[MAXCPU]; 6343fe7d45SAlexander Motin #endif 6443fe7d45SAlexander Motin 65a157e425SAlexander Motin int cpu_disable_deep_sleep = 0; /* Timer dies in C3. */ 6643fe7d45SAlexander Motin 67a157e425SAlexander Motin static void setuptimer(void); 68a157e425SAlexander Motin static void loadtimer(struct bintime *now, int first); 69a157e425SAlexander Motin static int doconfigtimer(void); 70a157e425SAlexander Motin static void configtimer(int start); 71a157e425SAlexander Motin static int round_freq(struct eventtimer *et, int freq); 7243fe7d45SAlexander Motin 73a157e425SAlexander Motin static void getnextcpuevent(struct bintime *event, int idle); 74a157e425SAlexander Motin static void getnextevent(struct bintime *event); 75a157e425SAlexander Motin static int handleevents(struct bintime *now, int fake); 76a157e425SAlexander Motin #ifdef SMP 77a157e425SAlexander Motin static void cpu_new_callout(int cpu, int ticks); 78a157e425SAlexander Motin #endif 7943fe7d45SAlexander Motin 80a157e425SAlexander Motin static struct mtx et_hw_mtx; 81a157e425SAlexander Motin 82a157e425SAlexander Motin #define ET_HW_LOCK(state) \ 83a157e425SAlexander Motin { \ 84a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 85a157e425SAlexander Motin mtx_lock_spin(&(state)->et_hw_mtx); \ 86a157e425SAlexander Motin else \ 87a157e425SAlexander Motin mtx_lock_spin(&et_hw_mtx); \ 88a157e425SAlexander Motin } 89a157e425SAlexander Motin 90a157e425SAlexander Motin #define ET_HW_UNLOCK(state) \ 91a157e425SAlexander Motin { \ 92a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 93a157e425SAlexander Motin mtx_unlock_spin(&(state)->et_hw_mtx); \ 94a157e425SAlexander Motin else \ 95a157e425SAlexander Motin mtx_unlock_spin(&et_hw_mtx); \ 96a157e425SAlexander Motin } 97a157e425SAlexander Motin 98a157e425SAlexander Motin static struct eventtimer *timer = NULL; 99a157e425SAlexander Motin static struct bintime timerperiod; /* Timer period for periodic mode. */ 100a157e425SAlexander Motin static struct bintime hardperiod; /* hardclock() events period. */ 101a157e425SAlexander Motin static struct bintime statperiod; /* statclock() events period. */ 102a157e425SAlexander Motin static struct bintime profperiod; /* profclock() events period. */ 103a157e425SAlexander Motin static struct bintime nexttick; /* Next global timer tick time. */ 104a157e425SAlexander Motin static u_int busy = 0; /* Reconfiguration is in progress. */ 105a157e425SAlexander Motin static int profiling = 0; /* Profiling events enabled. */ 106a157e425SAlexander Motin 107a157e425SAlexander Motin static char timername[32]; /* Wanted timer. */ 108a157e425SAlexander Motin TUNABLE_STR("kern.eventtimer.timer", timername, sizeof(timername)); 109a157e425SAlexander Motin 110dd9595e7SAlexander Motin static int singlemul = 0; /* Multiplier for periodic mode. */ 11143fe7d45SAlexander Motin TUNABLE_INT("kern.eventtimer.singlemul", &singlemul); 11243fe7d45SAlexander Motin SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul, 113a157e425SAlexander Motin 0, "Multiplier for periodic mode"); 11443fe7d45SAlexander Motin 115a157e425SAlexander Motin static u_int idletick = 0; /* Idle mode allowed. */ 116a157e425SAlexander Motin TUNABLE_INT("kern.eventtimer.idletick", &idletick); 117a157e425SAlexander Motin SYSCTL_INT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RW, &idletick, 118a157e425SAlexander Motin 0, "Run periodic events when idle"); 119a157e425SAlexander Motin 120a157e425SAlexander Motin static int periodic = 0; /* Periodic or one-shot mode. */ 121afe41f2dSAlexander Motin static int want_periodic = 0; /* What mode to prefer. */ 122afe41f2dSAlexander Motin TUNABLE_INT("kern.eventtimer.periodic", &want_periodic); 123a157e425SAlexander Motin 124a157e425SAlexander Motin struct pcpu_state { 125a157e425SAlexander Motin struct mtx et_hw_mtx; /* Per-CPU timer mutex. */ 126a157e425SAlexander Motin u_int action; /* Reconfiguration requests. */ 127a157e425SAlexander Motin u_int handle; /* Immediate handle resuests. */ 128a157e425SAlexander Motin struct bintime now; /* Last tick time. */ 129a157e425SAlexander Motin struct bintime nextevent; /* Next scheduled event on this CPU. */ 130a157e425SAlexander Motin struct bintime nexttick; /* Next timer tick time. */ 131a157e425SAlexander Motin struct bintime nexthard; /* Next hardlock() event. */ 132a157e425SAlexander Motin struct bintime nextstat; /* Next statclock() event. */ 133a157e425SAlexander Motin struct bintime nextprof; /* Next profclock() event. */ 134a157e425SAlexander Motin int ipi; /* This CPU needs IPI. */ 135a157e425SAlexander Motin int idle; /* This CPU is in idle mode. */ 136a157e425SAlexander Motin }; 137a157e425SAlexander Motin 138a157e425SAlexander Motin static DPCPU_DEFINE(struct pcpu_state, timerstate); 13943fe7d45SAlexander Motin 14043fe7d45SAlexander Motin #define FREQ2BT(freq, bt) \ 14143fe7d45SAlexander Motin { \ 14243fe7d45SAlexander Motin (bt)->sec = 0; \ 14343fe7d45SAlexander Motin (bt)->frac = ((uint64_t)0x8000000000000000 / (freq)) << 1; \ 14443fe7d45SAlexander Motin } 14551636352SAlexander Motin #define BT2FREQ(bt) \ 14651636352SAlexander Motin (((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \ 14751636352SAlexander Motin ((bt)->frac >> 1)) 14843fe7d45SAlexander Motin 149a157e425SAlexander Motin /* 150a157e425SAlexander Motin * Timer broadcast IPI handler. 151a157e425SAlexander Motin */ 152a157e425SAlexander Motin int 153a157e425SAlexander Motin hardclockintr(void) 15443fe7d45SAlexander Motin { 155a157e425SAlexander Motin struct bintime now; 156a157e425SAlexander Motin struct pcpu_state *state; 157a157e425SAlexander Motin int done; 15843fe7d45SAlexander Motin 159a157e425SAlexander Motin if (doconfigtimer() || busy) 160a157e425SAlexander Motin return (FILTER_HANDLED); 161a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 162a157e425SAlexander Motin now = state->now; 163a157e425SAlexander Motin CTR4(KTR_SPARE2, "ipi at %d: now %d.%08x%08x", 164a157e425SAlexander Motin curcpu, now.sec, (unsigned int)(now.frac >> 32), 165a157e425SAlexander Motin (unsigned int)(now.frac & 0xffffffff)); 166a157e425SAlexander Motin done = handleevents(&now, 0); 167a157e425SAlexander Motin return (done ? FILTER_HANDLED : FILTER_STRAY); 168a157e425SAlexander Motin } 169a157e425SAlexander Motin 170a157e425SAlexander Motin /* 171a157e425SAlexander Motin * Handle all events for specified time on this CPU 172a157e425SAlexander Motin */ 173a157e425SAlexander Motin static int 174a157e425SAlexander Motin handleevents(struct bintime *now, int fake) 175a157e425SAlexander Motin { 176a157e425SAlexander Motin struct bintime t; 177a157e425SAlexander Motin struct trapframe *frame; 178a157e425SAlexander Motin struct pcpu_state *state; 179a157e425SAlexander Motin uintfptr_t pc; 180a157e425SAlexander Motin int usermode; 181a157e425SAlexander Motin int done, runs; 182a157e425SAlexander Motin 183a157e425SAlexander Motin CTR4(KTR_SPARE2, "handle at %d: now %d.%08x%08x", 184a157e425SAlexander Motin curcpu, now->sec, (unsigned int)(now->frac >> 32), 185a157e425SAlexander Motin (unsigned int)(now->frac & 0xffffffff)); 186a157e425SAlexander Motin done = 0; 187a157e425SAlexander Motin if (fake) { 188a157e425SAlexander Motin frame = NULL; 189a157e425SAlexander Motin usermode = 0; 190a157e425SAlexander Motin pc = 0; 191a157e425SAlexander Motin } else { 192a157e425SAlexander Motin frame = curthread->td_intr_frame; 193a157e425SAlexander Motin usermode = TRAPF_USERMODE(frame); 194a157e425SAlexander Motin pc = TRAPF_PC(frame); 195a157e425SAlexander Motin } 19643fe7d45SAlexander Motin #ifdef KDTRACE_HOOKS 19743fe7d45SAlexander Motin /* 19843fe7d45SAlexander Motin * If the DTrace hooks are configured and a callback function 19943fe7d45SAlexander Motin * has been registered, then call it to process the high speed 20043fe7d45SAlexander Motin * timers. 20143fe7d45SAlexander Motin */ 202a157e425SAlexander Motin if (!fake && cyclic_clock_func[curcpu] != NULL) 203a157e425SAlexander Motin (*cyclic_clock_func[curcpu])(frame); 20443fe7d45SAlexander Motin #endif 205a157e425SAlexander Motin runs = 0; 206a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 207a157e425SAlexander Motin while (bintime_cmp(now, &state->nexthard, >=)) { 208a157e425SAlexander Motin bintime_add(&state->nexthard, &hardperiod); 209a157e425SAlexander Motin runs++; 21043fe7d45SAlexander Motin } 211*c70410e6SAlexander Motin if (runs && fake < 2) { 212a157e425SAlexander Motin hardclock_anycpu(runs, usermode); 213a157e425SAlexander Motin done = 1; 21443fe7d45SAlexander Motin } 215a157e425SAlexander Motin while (bintime_cmp(now, &state->nextstat, >=)) { 216*c70410e6SAlexander Motin if (fake < 2) 217a157e425SAlexander Motin statclock(usermode); 218a157e425SAlexander Motin bintime_add(&state->nextstat, &statperiod); 219a157e425SAlexander Motin done = 1; 22043fe7d45SAlexander Motin } 221a157e425SAlexander Motin if (profiling) { 222a157e425SAlexander Motin while (bintime_cmp(now, &state->nextprof, >=)) { 223a157e425SAlexander Motin if (!fake) 224a157e425SAlexander Motin profclock(usermode, pc); 225a157e425SAlexander Motin bintime_add(&state->nextprof, &profperiod); 226a157e425SAlexander Motin done = 1; 22743fe7d45SAlexander Motin } 228a157e425SAlexander Motin } else 229a157e425SAlexander Motin state->nextprof = state->nextstat; 230a157e425SAlexander Motin getnextcpuevent(&t, 0); 231*c70410e6SAlexander Motin if (fake == 2) { 232*c70410e6SAlexander Motin state->nextevent = t; 233*c70410e6SAlexander Motin return (done); 234*c70410e6SAlexander Motin } 235a157e425SAlexander Motin ET_HW_LOCK(state); 236a157e425SAlexander Motin if (!busy) { 237a157e425SAlexander Motin state->idle = 0; 238a157e425SAlexander Motin state->nextevent = t; 239a157e425SAlexander Motin loadtimer(now, 0); 24043fe7d45SAlexander Motin } 241a157e425SAlexander Motin ET_HW_UNLOCK(state); 242a157e425SAlexander Motin return (done); 24343fe7d45SAlexander Motin } 24443fe7d45SAlexander Motin 24543fe7d45SAlexander Motin /* 246a157e425SAlexander Motin * Schedule binuptime of the next event on current CPU. 24743fe7d45SAlexander Motin */ 24843fe7d45SAlexander Motin static void 249a157e425SAlexander Motin getnextcpuevent(struct bintime *event, int idle) 25043fe7d45SAlexander Motin { 251a157e425SAlexander Motin struct bintime tmp; 252a157e425SAlexander Motin struct pcpu_state *state; 253a157e425SAlexander Motin int skip; 25443fe7d45SAlexander Motin 255a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 256a157e425SAlexander Motin *event = state->nexthard; 257a157e425SAlexander Motin if (idle) { /* If CPU is idle - ask callouts for how long. */ 2580e189873SAlexander Motin skip = 4; 2590e189873SAlexander Motin if (curcpu == CPU_FIRST() && tc_min_ticktock_freq > skip) 2600e189873SAlexander Motin skip = tc_min_ticktock_freq; 2610e189873SAlexander Motin skip = callout_tickstofirst(hz / skip) - 1; 262a157e425SAlexander Motin CTR2(KTR_SPARE2, "skip at %d: %d", curcpu, skip); 263a157e425SAlexander Motin tmp = hardperiod; 264a157e425SAlexander Motin bintime_mul(&tmp, skip); 265a157e425SAlexander Motin bintime_add(event, &tmp); 266a157e425SAlexander Motin } else { /* If CPU is active - handle all types of events. */ 267a157e425SAlexander Motin if (bintime_cmp(event, &state->nextstat, >)) 268a157e425SAlexander Motin *event = state->nextstat; 269a157e425SAlexander Motin if (profiling && 270a157e425SAlexander Motin bintime_cmp(event, &state->nextprof, >)) 271a157e425SAlexander Motin *event = state->nextprof; 27243fe7d45SAlexander Motin } 27343fe7d45SAlexander Motin } 274a157e425SAlexander Motin 275a157e425SAlexander Motin /* 276a157e425SAlexander Motin * Schedule binuptime of the next event on all CPUs. 277a157e425SAlexander Motin */ 278a157e425SAlexander Motin static void 279a157e425SAlexander Motin getnextevent(struct bintime *event) 280a157e425SAlexander Motin { 281a157e425SAlexander Motin struct pcpu_state *state; 282a157e425SAlexander Motin #ifdef SMP 283a157e425SAlexander Motin int cpu; 284a157e425SAlexander Motin #endif 285a157e425SAlexander Motin int c; 286a157e425SAlexander Motin 287a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 288a157e425SAlexander Motin *event = state->nextevent; 289a157e425SAlexander Motin c = curcpu; 290a157e425SAlexander Motin #ifdef SMP 291a157e425SAlexander Motin if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) { 292a157e425SAlexander Motin CPU_FOREACH(cpu) { 293a157e425SAlexander Motin if (curcpu == cpu) 294a157e425SAlexander Motin continue; 295a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 296a157e425SAlexander Motin if (bintime_cmp(event, &state->nextevent, >)) { 297a157e425SAlexander Motin *event = state->nextevent; 298a157e425SAlexander Motin c = cpu; 29943fe7d45SAlexander Motin } 30043fe7d45SAlexander Motin } 301a157e425SAlexander Motin } 302a157e425SAlexander Motin #endif 303a157e425SAlexander Motin CTR5(KTR_SPARE2, "next at %d: next %d.%08x%08x by %d", 304a157e425SAlexander Motin curcpu, event->sec, (unsigned int)(event->frac >> 32), 305a157e425SAlexander Motin (unsigned int)(event->frac & 0xffffffff), c); 306a157e425SAlexander Motin } 307a157e425SAlexander Motin 308a157e425SAlexander Motin /* Hardware timer callback function. */ 309a157e425SAlexander Motin static void 310a157e425SAlexander Motin timercb(struct eventtimer *et, void *arg) 311a157e425SAlexander Motin { 312a157e425SAlexander Motin struct bintime now; 313a157e425SAlexander Motin struct bintime *next; 314a157e425SAlexander Motin struct pcpu_state *state; 315a157e425SAlexander Motin #ifdef SMP 316a157e425SAlexander Motin int cpu, bcast; 317a157e425SAlexander Motin #endif 318a157e425SAlexander Motin 319a157e425SAlexander Motin /* Do not touch anything if somebody reconfiguring timers. */ 320a157e425SAlexander Motin if (busy) 321a157e425SAlexander Motin return; 322a157e425SAlexander Motin /* Update present and next tick times. */ 323a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 324a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_PERCPU) { 325a157e425SAlexander Motin next = &state->nexttick; 326a157e425SAlexander Motin } else 327a157e425SAlexander Motin next = &nexttick; 328a157e425SAlexander Motin if (periodic) { 329a157e425SAlexander Motin now = *next; /* Ex-next tick time becomes present time. */ 330a157e425SAlexander Motin bintime_add(next, &timerperiod); /* Next tick in 1 period. */ 331a157e425SAlexander Motin } else { 332a157e425SAlexander Motin binuptime(&now); /* Get present time from hardware. */ 333a157e425SAlexander Motin next->sec = -1; /* Next tick is not scheduled yet. */ 334a157e425SAlexander Motin } 335a157e425SAlexander Motin state->now = now; 336a157e425SAlexander Motin CTR4(KTR_SPARE2, "intr at %d: now %d.%08x%08x", 337a157e425SAlexander Motin curcpu, now.sec, (unsigned int)(now.frac >> 32), 338a157e425SAlexander Motin (unsigned int)(now.frac & 0xffffffff)); 339a157e425SAlexander Motin 340a157e425SAlexander Motin #ifdef SMP 341a157e425SAlexander Motin /* Prepare broadcasting to other CPUs for non-per-CPU timers. */ 342a157e425SAlexander Motin bcast = 0; 343a157e425SAlexander Motin if ((et->et_flags & ET_FLAGS_PERCPU) == 0 && smp_started) { 344a157e425SAlexander Motin CPU_FOREACH(cpu) { 345a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 346a157e425SAlexander Motin ET_HW_LOCK(state); 347a157e425SAlexander Motin state->now = now; 348a157e425SAlexander Motin if (bintime_cmp(&now, &state->nextevent, >=)) { 349a157e425SAlexander Motin state->nextevent.sec++; 3508e860de4SAlexander Motin if (curcpu != cpu) { 351a157e425SAlexander Motin state->ipi = 1; 352a157e425SAlexander Motin bcast = 1; 353a157e425SAlexander Motin } 3548e860de4SAlexander Motin } 355a157e425SAlexander Motin ET_HW_UNLOCK(state); 356a157e425SAlexander Motin } 357a157e425SAlexander Motin } 358a157e425SAlexander Motin #endif 359a157e425SAlexander Motin 360a157e425SAlexander Motin /* Handle events for this time on this CPU. */ 361a157e425SAlexander Motin handleevents(&now, 0); 362a157e425SAlexander Motin 363a157e425SAlexander Motin #ifdef SMP 364a157e425SAlexander Motin /* Broadcast interrupt to other CPUs for non-per-CPU timers. */ 365a157e425SAlexander Motin if (bcast) { 366a157e425SAlexander Motin CPU_FOREACH(cpu) { 367a157e425SAlexander Motin if (curcpu == cpu) 368a157e425SAlexander Motin continue; 369a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 370a157e425SAlexander Motin if (state->ipi) { 371a157e425SAlexander Motin state->ipi = 0; 372a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 373a157e425SAlexander Motin } 374a157e425SAlexander Motin } 375a157e425SAlexander Motin } 376a157e425SAlexander Motin #endif 377a157e425SAlexander Motin } 378a157e425SAlexander Motin 379a157e425SAlexander Motin /* 380a157e425SAlexander Motin * Load new value into hardware timer. 381a157e425SAlexander Motin */ 382a157e425SAlexander Motin static void 383a157e425SAlexander Motin loadtimer(struct bintime *now, int start) 384a157e425SAlexander Motin { 385a157e425SAlexander Motin struct pcpu_state *state; 386a157e425SAlexander Motin struct bintime new; 387a157e425SAlexander Motin struct bintime *next; 388a157e425SAlexander Motin uint64_t tmp; 389a157e425SAlexander Motin int eq; 390a157e425SAlexander Motin 391*c70410e6SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) { 392*c70410e6SAlexander Motin state = DPCPU_PTR(timerstate); 393*c70410e6SAlexander Motin next = &state->nexttick; 394*c70410e6SAlexander Motin } else 395*c70410e6SAlexander Motin next = &nexttick; 396a157e425SAlexander Motin if (periodic) { 397a157e425SAlexander Motin if (start) { 398a157e425SAlexander Motin /* 399a157e425SAlexander Motin * Try to start all periodic timers aligned 400a157e425SAlexander Motin * to period to make events synchronous. 401a157e425SAlexander Motin */ 402a157e425SAlexander Motin tmp = ((uint64_t)now->sec << 36) + (now->frac >> 28); 403a157e425SAlexander Motin tmp = (tmp % (timerperiod.frac >> 28)) << 28; 404*c70410e6SAlexander Motin new.sec = 0; 405*c70410e6SAlexander Motin new.frac = timerperiod.frac - tmp; 406*c70410e6SAlexander Motin if (new.frac < tmp) /* Left less then passed. */ 407*c70410e6SAlexander Motin bintime_add(&new, &timerperiod); 408a157e425SAlexander Motin CTR5(KTR_SPARE2, "load p at %d: now %d.%08x first in %d.%08x", 409a157e425SAlexander Motin curcpu, now->sec, (unsigned int)(now->frac >> 32), 410a157e425SAlexander Motin new.sec, (unsigned int)(new.frac >> 32)); 411*c70410e6SAlexander Motin *next = new; 412*c70410e6SAlexander Motin bintime_add(next, now); 413a157e425SAlexander Motin et_start(timer, &new, &timerperiod); 414a157e425SAlexander Motin } 415a157e425SAlexander Motin } else { 416a157e425SAlexander Motin getnextevent(&new); 417a157e425SAlexander Motin eq = bintime_cmp(&new, next, ==); 418a157e425SAlexander Motin CTR5(KTR_SPARE2, "load at %d: next %d.%08x%08x eq %d", 419a157e425SAlexander Motin curcpu, new.sec, (unsigned int)(new.frac >> 32), 420a157e425SAlexander Motin (unsigned int)(new.frac & 0xffffffff), 421a157e425SAlexander Motin eq); 422a157e425SAlexander Motin if (!eq) { 423a157e425SAlexander Motin *next = new; 424a157e425SAlexander Motin bintime_sub(&new, now); 425a157e425SAlexander Motin et_start(timer, &new, NULL); 426a157e425SAlexander Motin } 427a157e425SAlexander Motin } 428a157e425SAlexander Motin } 429a157e425SAlexander Motin 430a157e425SAlexander Motin /* 431a157e425SAlexander Motin * Prepare event timer parameters after configuration changes. 432a157e425SAlexander Motin */ 433a157e425SAlexander Motin static void 434a157e425SAlexander Motin setuptimer(void) 435a157e425SAlexander Motin { 436a157e425SAlexander Motin int freq; 437a157e425SAlexander Motin 438a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 439a157e425SAlexander Motin periodic = 0; 440a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 441a157e425SAlexander Motin periodic = 1; 442dd9595e7SAlexander Motin singlemul = MIN(MAX(singlemul, 1), 20); 443a157e425SAlexander Motin freq = hz * singlemul; 444a157e425SAlexander Motin while (freq < (profiling ? profhz : stathz)) 445a157e425SAlexander Motin freq += hz; 446a157e425SAlexander Motin freq = round_freq(timer, freq); 447a157e425SAlexander Motin FREQ2BT(freq, &timerperiod); 448a157e425SAlexander Motin } 44943fe7d45SAlexander Motin 45043fe7d45SAlexander Motin /* 45143fe7d45SAlexander Motin * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler. 45243fe7d45SAlexander Motin */ 453a157e425SAlexander Motin static int 454a157e425SAlexander Motin doconfigtimer(void) 45543fe7d45SAlexander Motin { 456a157e425SAlexander Motin struct bintime now; 457a157e425SAlexander Motin struct pcpu_state *state; 45843fe7d45SAlexander Motin 459a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 460a157e425SAlexander Motin switch (atomic_load_acq_int(&state->action)) { 461a157e425SAlexander Motin case 1: 462a157e425SAlexander Motin binuptime(&now); 463a157e425SAlexander Motin ET_HW_LOCK(state); 464a157e425SAlexander Motin loadtimer(&now, 1); 465a157e425SAlexander Motin ET_HW_UNLOCK(state); 466a157e425SAlexander Motin state->handle = 0; 467a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 468a157e425SAlexander Motin return (1); 469a157e425SAlexander Motin case 2: 470a157e425SAlexander Motin ET_HW_LOCK(state); 471a157e425SAlexander Motin et_stop(timer); 472a157e425SAlexander Motin ET_HW_UNLOCK(state); 473a157e425SAlexander Motin state->handle = 0; 474a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 475a157e425SAlexander Motin return (1); 476a157e425SAlexander Motin } 477a157e425SAlexander Motin if (atomic_readandclear_int(&state->handle) && !busy) { 478a157e425SAlexander Motin binuptime(&now); 479a157e425SAlexander Motin handleevents(&now, 0); 48043fe7d45SAlexander Motin return (1); 48143fe7d45SAlexander Motin } 48243fe7d45SAlexander Motin return (0); 48343fe7d45SAlexander Motin } 48443fe7d45SAlexander Motin 48543fe7d45SAlexander Motin /* 48643fe7d45SAlexander Motin * Reconfigure specified timer. 48743fe7d45SAlexander Motin * For per-CPU timers use IPI to make other CPUs to reconfigure. 48843fe7d45SAlexander Motin */ 48943fe7d45SAlexander Motin static void 490a157e425SAlexander Motin configtimer(int start) 49143fe7d45SAlexander Motin { 492a157e425SAlexander Motin struct bintime now, next; 493a157e425SAlexander Motin struct pcpu_state *state; 49443fe7d45SAlexander Motin int cpu; 49543fe7d45SAlexander Motin 496a157e425SAlexander Motin if (start) { 497a157e425SAlexander Motin setuptimer(); 498a157e425SAlexander Motin binuptime(&now); 499a157e425SAlexander Motin } 50043fe7d45SAlexander Motin critical_enter(); 501a157e425SAlexander Motin ET_HW_LOCK(DPCPU_PTR(timerstate)); 502a157e425SAlexander Motin if (start) { 503a157e425SAlexander Motin /* Initialize time machine parameters. */ 504a157e425SAlexander Motin next = now; 505a157e425SAlexander Motin bintime_add(&next, &timerperiod); 506a157e425SAlexander Motin if (periodic) 507a157e425SAlexander Motin nexttick = next; 50843fe7d45SAlexander Motin else 509a157e425SAlexander Motin nexttick.sec = -1; 510a157e425SAlexander Motin CPU_FOREACH(cpu) { 511a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 512a157e425SAlexander Motin state->now = now; 513a157e425SAlexander Motin state->nextevent = next; 514a157e425SAlexander Motin if (periodic) 515a157e425SAlexander Motin state->nexttick = next; 516a157e425SAlexander Motin else 517a157e425SAlexander Motin state->nexttick.sec = -1; 518a157e425SAlexander Motin state->nexthard = next; 519a157e425SAlexander Motin state->nextstat = next; 520a157e425SAlexander Motin state->nextprof = next; 521a157e425SAlexander Motin hardclock_sync(cpu); 522a157e425SAlexander Motin } 523a157e425SAlexander Motin busy = 0; 524a157e425SAlexander Motin /* Start global timer or per-CPU timer of this CPU. */ 525a157e425SAlexander Motin loadtimer(&now, 1); 526a157e425SAlexander Motin } else { 527a157e425SAlexander Motin busy = 1; 528a157e425SAlexander Motin /* Stop global timer or per-CPU timer of this CPU. */ 529a157e425SAlexander Motin et_stop(timer); 530a157e425SAlexander Motin } 531a157e425SAlexander Motin ET_HW_UNLOCK(DPCPU_PTR(timerstate)); 53243fe7d45SAlexander Motin #ifdef SMP 533a157e425SAlexander Motin /* If timer is global or there is no other CPUs yet - we are done. */ 534a157e425SAlexander Motin if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) { 53543fe7d45SAlexander Motin critical_exit(); 53643fe7d45SAlexander Motin return; 53743fe7d45SAlexander Motin } 53843fe7d45SAlexander Motin /* Set reconfigure flags for other CPUs. */ 53943fe7d45SAlexander Motin CPU_FOREACH(cpu) { 540a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 541a157e425SAlexander Motin atomic_store_rel_int(&state->action, 542a157e425SAlexander Motin (cpu == curcpu) ? 0 : ( start ? 1 : 2)); 54343fe7d45SAlexander Motin } 544a157e425SAlexander Motin /* Broadcast reconfigure IPI. */ 545a157e425SAlexander Motin ipi_all_but_self(IPI_HARDCLOCK); 54643fe7d45SAlexander Motin /* Wait for reconfiguration completed. */ 54743fe7d45SAlexander Motin restart: 54843fe7d45SAlexander Motin cpu_spinwait(); 54943fe7d45SAlexander Motin CPU_FOREACH(cpu) { 55043fe7d45SAlexander Motin if (cpu == curcpu) 55143fe7d45SAlexander Motin continue; 552a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 553a157e425SAlexander Motin if (atomic_load_acq_int(&state->action)) 55443fe7d45SAlexander Motin goto restart; 55543fe7d45SAlexander Motin } 55643fe7d45SAlexander Motin #endif 557a157e425SAlexander Motin critical_exit(); 55843fe7d45SAlexander Motin } 55943fe7d45SAlexander Motin 560a157e425SAlexander Motin /* 561a157e425SAlexander Motin * Calculate nearest frequency supported by hardware timer. 562a157e425SAlexander Motin */ 56351636352SAlexander Motin static int 56451636352SAlexander Motin round_freq(struct eventtimer *et, int freq) 56551636352SAlexander Motin { 56651636352SAlexander Motin uint64_t div; 56751636352SAlexander Motin 56851636352SAlexander Motin if (et->et_frequency != 0) { 569599cf0f1SAlexander Motin div = lmax((et->et_frequency + freq / 2) / freq, 1); 57051636352SAlexander Motin if (et->et_flags & ET_FLAGS_POW2DIV) 57151636352SAlexander Motin div = 1 << (flsl(div + div / 2) - 1); 57251636352SAlexander Motin freq = (et->et_frequency + div / 2) / div; 57351636352SAlexander Motin } 57451636352SAlexander Motin if (et->et_min_period.sec > 0) 57551636352SAlexander Motin freq = 0; 576599cf0f1SAlexander Motin else if (et->et_min_period.frac != 0) 57751636352SAlexander Motin freq = min(freq, BT2FREQ(&et->et_min_period)); 57851636352SAlexander Motin if (et->et_max_period.sec == 0 && et->et_max_period.frac != 0) 57951636352SAlexander Motin freq = max(freq, BT2FREQ(&et->et_max_period)); 58051636352SAlexander Motin return (freq); 58151636352SAlexander Motin } 58251636352SAlexander Motin 58343fe7d45SAlexander Motin /* 584a157e425SAlexander Motin * Configure and start event timers (BSP part). 58543fe7d45SAlexander Motin */ 58643fe7d45SAlexander Motin void 58743fe7d45SAlexander Motin cpu_initclocks_bsp(void) 58843fe7d45SAlexander Motin { 589a157e425SAlexander Motin struct pcpu_state *state; 590a157e425SAlexander Motin int base, div, cpu; 59143fe7d45SAlexander Motin 592a157e425SAlexander Motin mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 593a157e425SAlexander Motin CPU_FOREACH(cpu) { 594a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 595a157e425SAlexander Motin mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 596a157e425SAlexander Motin } 597a157e425SAlexander Motin #ifdef SMP 598a157e425SAlexander Motin callout_new_inserted = cpu_new_callout; 599a157e425SAlexander Motin #endif 600afe41f2dSAlexander Motin periodic = want_periodic; 601a157e425SAlexander Motin /* Grab requested timer or the best of present. */ 602a157e425SAlexander Motin if (timername[0]) 603a157e425SAlexander Motin timer = et_find(timername, 0, 0); 604a157e425SAlexander Motin if (timer == NULL && periodic) { 605a157e425SAlexander Motin timer = et_find(NULL, 60643fe7d45SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 607a157e425SAlexander Motin } 608a157e425SAlexander Motin if (timer == NULL) { 609a157e425SAlexander Motin timer = et_find(NULL, 610a157e425SAlexander Motin ET_FLAGS_ONESHOT, ET_FLAGS_ONESHOT); 611a157e425SAlexander Motin } 612a157e425SAlexander Motin if (timer == NULL && !periodic) { 613a157e425SAlexander Motin timer = et_find(NULL, 614a157e425SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 615a157e425SAlexander Motin } 616a157e425SAlexander Motin if (timer == NULL) 617a157e425SAlexander Motin panic("No usable event timer found!"); 618a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 619a157e425SAlexander Motin 620a157e425SAlexander Motin /* Adapt to timer capabilities. */ 621a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 622a157e425SAlexander Motin periodic = 0; 623a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 624a157e425SAlexander Motin periodic = 1; 625a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 626a157e425SAlexander Motin cpu_disable_deep_sleep++; 627a157e425SAlexander Motin 62843fe7d45SAlexander Motin /* 62943fe7d45SAlexander Motin * We honor the requested 'hz' value. 63043fe7d45SAlexander Motin * We want to run stathz in the neighborhood of 128hz. 63143fe7d45SAlexander Motin * We would like profhz to run as often as possible. 63243fe7d45SAlexander Motin */ 633dd9595e7SAlexander Motin if (singlemul <= 0 || singlemul > 20) { 63443fe7d45SAlexander Motin if (hz >= 1500 || (hz % 128) == 0) 63543fe7d45SAlexander Motin singlemul = 1; 63643fe7d45SAlexander Motin else if (hz >= 750) 63743fe7d45SAlexander Motin singlemul = 2; 63843fe7d45SAlexander Motin else 63943fe7d45SAlexander Motin singlemul = 4; 64043fe7d45SAlexander Motin } 641a157e425SAlexander Motin if (periodic) { 642a157e425SAlexander Motin base = round_freq(timer, hz * singlemul); 64351636352SAlexander Motin singlemul = max((base + hz / 2) / hz, 1); 64451636352SAlexander Motin hz = (base + singlemul / 2) / singlemul; 64551636352SAlexander Motin if (base <= 128) 64643fe7d45SAlexander Motin stathz = base; 64743fe7d45SAlexander Motin else { 64843fe7d45SAlexander Motin div = base / 128; 64951636352SAlexander Motin if (div >= singlemul && (div % singlemul) == 0) 65043fe7d45SAlexander Motin div++; 65143fe7d45SAlexander Motin stathz = base / div; 65243fe7d45SAlexander Motin } 65343fe7d45SAlexander Motin profhz = stathz; 65451636352SAlexander Motin while ((profhz + stathz) <= 128 * 64) 65543fe7d45SAlexander Motin profhz += stathz; 656a157e425SAlexander Motin profhz = round_freq(timer, profhz); 65743fe7d45SAlexander Motin } else { 658a157e425SAlexander Motin hz = round_freq(timer, hz); 659a157e425SAlexander Motin stathz = round_freq(timer, 127); 660a157e425SAlexander Motin profhz = round_freq(timer, stathz * 64); 66143fe7d45SAlexander Motin } 662599cf0f1SAlexander Motin tick = 1000000 / hz; 663a157e425SAlexander Motin FREQ2BT(hz, &hardperiod); 664a157e425SAlexander Motin FREQ2BT(stathz, &statperiod); 665a157e425SAlexander Motin FREQ2BT(profhz, &profperiod); 66643fe7d45SAlexander Motin ET_LOCK(); 667a157e425SAlexander Motin configtimer(1); 66843fe7d45SAlexander Motin ET_UNLOCK(); 66943fe7d45SAlexander Motin } 67043fe7d45SAlexander Motin 671a157e425SAlexander Motin /* 672a157e425SAlexander Motin * Start per-CPU event timers on APs. 673a157e425SAlexander Motin */ 67443fe7d45SAlexander Motin void 67543fe7d45SAlexander Motin cpu_initclocks_ap(void) 67643fe7d45SAlexander Motin { 677a157e425SAlexander Motin struct bintime now; 678a157e425SAlexander Motin struct pcpu_state *state; 67943fe7d45SAlexander Motin 680a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 681a157e425SAlexander Motin binuptime(&now); 682a157e425SAlexander Motin ET_HW_LOCK(state); 683*c70410e6SAlexander Motin if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 && periodic) { 684*c70410e6SAlexander Motin state->now = nexttick; 685*c70410e6SAlexander Motin bintime_sub(&state->now, &timerperiod); 686*c70410e6SAlexander Motin } else 687*c70410e6SAlexander Motin state->now = now; 688*c70410e6SAlexander Motin hardclock_sync(curcpu); 689*c70410e6SAlexander Motin handleevents(&state->now, 2); 690*c70410e6SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) 691a157e425SAlexander Motin loadtimer(&now, 1); 692a157e425SAlexander Motin ET_HW_UNLOCK(state); 69343fe7d45SAlexander Motin } 69443fe7d45SAlexander Motin 695a157e425SAlexander Motin /* 696a157e425SAlexander Motin * Switch to profiling clock rates. 697a157e425SAlexander Motin */ 69843fe7d45SAlexander Motin void 69943fe7d45SAlexander Motin cpu_startprofclock(void) 70043fe7d45SAlexander Motin { 70143fe7d45SAlexander Motin 70243fe7d45SAlexander Motin ET_LOCK(); 703a157e425SAlexander Motin if (periodic) { 704a157e425SAlexander Motin configtimer(0); 705a157e425SAlexander Motin profiling = 1; 706a157e425SAlexander Motin configtimer(1); 707a157e425SAlexander Motin } else 708a157e425SAlexander Motin profiling = 1; 70943fe7d45SAlexander Motin ET_UNLOCK(); 71043fe7d45SAlexander Motin } 71143fe7d45SAlexander Motin 712a157e425SAlexander Motin /* 713a157e425SAlexander Motin * Switch to regular clock rates. 714a157e425SAlexander Motin */ 71543fe7d45SAlexander Motin void 71643fe7d45SAlexander Motin cpu_stopprofclock(void) 71743fe7d45SAlexander Motin { 71843fe7d45SAlexander Motin 71943fe7d45SAlexander Motin ET_LOCK(); 720a157e425SAlexander Motin if (periodic) { 721a157e425SAlexander Motin configtimer(0); 722a157e425SAlexander Motin profiling = 0; 723a157e425SAlexander Motin configtimer(1); 724a157e425SAlexander Motin } else 725a157e425SAlexander Motin profiling = 0; 72643fe7d45SAlexander Motin ET_UNLOCK(); 72743fe7d45SAlexander Motin } 72843fe7d45SAlexander Motin 729a157e425SAlexander Motin /* 730a157e425SAlexander Motin * Switch to idle mode (all ticks handled). 731a157e425SAlexander Motin */ 732a157e425SAlexander Motin void 733a157e425SAlexander Motin cpu_idleclock(void) 734a157e425SAlexander Motin { 735a157e425SAlexander Motin struct bintime now, t; 736a157e425SAlexander Motin struct pcpu_state *state; 737a157e425SAlexander Motin 738a157e425SAlexander Motin if (idletick || busy || 7399dfc483cSAlexander Motin (periodic && (timer->et_flags & ET_FLAGS_PERCPU)) 7409dfc483cSAlexander Motin #ifdef DEVICE_POLLING 7419dfc483cSAlexander Motin || curcpu == CPU_FIRST() 7429dfc483cSAlexander Motin #endif 7439dfc483cSAlexander Motin ) 744a157e425SAlexander Motin return; 745a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 746a157e425SAlexander Motin if (periodic) 747a157e425SAlexander Motin now = state->now; 748a157e425SAlexander Motin else 749a157e425SAlexander Motin binuptime(&now); 750a157e425SAlexander Motin CTR4(KTR_SPARE2, "idle at %d: now %d.%08x%08x", 751a157e425SAlexander Motin curcpu, now.sec, (unsigned int)(now.frac >> 32), 752a157e425SAlexander Motin (unsigned int)(now.frac & 0xffffffff)); 753a157e425SAlexander Motin getnextcpuevent(&t, 1); 754a157e425SAlexander Motin ET_HW_LOCK(state); 755a157e425SAlexander Motin state->idle = 1; 756a157e425SAlexander Motin state->nextevent = t; 757a157e425SAlexander Motin if (!periodic) 758a157e425SAlexander Motin loadtimer(&now, 0); 759a157e425SAlexander Motin ET_HW_UNLOCK(state); 760a157e425SAlexander Motin } 761a157e425SAlexander Motin 762a157e425SAlexander Motin /* 763a157e425SAlexander Motin * Switch to active mode (skip empty ticks). 764a157e425SAlexander Motin */ 765a157e425SAlexander Motin void 766a157e425SAlexander Motin cpu_activeclock(void) 767a157e425SAlexander Motin { 768a157e425SAlexander Motin struct bintime now; 769a157e425SAlexander Motin struct pcpu_state *state; 770a157e425SAlexander Motin struct thread *td; 771a157e425SAlexander Motin 772a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 773a157e425SAlexander Motin if (state->idle == 0 || busy) 774a157e425SAlexander Motin return; 775a157e425SAlexander Motin if (periodic) 776a157e425SAlexander Motin now = state->now; 777a157e425SAlexander Motin else 778a157e425SAlexander Motin binuptime(&now); 779a157e425SAlexander Motin CTR4(KTR_SPARE2, "active at %d: now %d.%08x%08x", 780a157e425SAlexander Motin curcpu, now.sec, (unsigned int)(now.frac >> 32), 781a157e425SAlexander Motin (unsigned int)(now.frac & 0xffffffff)); 782a157e425SAlexander Motin spinlock_enter(); 783a157e425SAlexander Motin td = curthread; 784a157e425SAlexander Motin td->td_intr_nesting_level++; 785a157e425SAlexander Motin handleevents(&now, 1); 786a157e425SAlexander Motin td->td_intr_nesting_level--; 787a157e425SAlexander Motin spinlock_exit(); 788a157e425SAlexander Motin } 789a157e425SAlexander Motin 790a157e425SAlexander Motin #ifdef SMP 791a157e425SAlexander Motin static void 792a157e425SAlexander Motin cpu_new_callout(int cpu, int ticks) 793a157e425SAlexander Motin { 794a157e425SAlexander Motin struct bintime tmp; 795a157e425SAlexander Motin struct pcpu_state *state; 796a157e425SAlexander Motin 797a157e425SAlexander Motin CTR3(KTR_SPARE2, "new co at %d: on %d in %d", 798a157e425SAlexander Motin curcpu, cpu, ticks); 799a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 800a157e425SAlexander Motin ET_HW_LOCK(state); 801a157e425SAlexander Motin if (state->idle == 0 || busy) { 802a157e425SAlexander Motin ET_HW_UNLOCK(state); 803a157e425SAlexander Motin return; 804a157e425SAlexander Motin } 805a157e425SAlexander Motin /* 806a157e425SAlexander Motin * If timer is periodic - just update next event time for target CPU. 807bcb74c4cSAlexander Motin * If timer is global - there is chance it is already programmed. 808a157e425SAlexander Motin */ 809bcb74c4cSAlexander Motin if (periodic || (timer->et_flags & ET_FLAGS_PERCPU) == 0) { 810a157e425SAlexander Motin state->nextevent = state->nexthard; 811a157e425SAlexander Motin tmp = hardperiod; 812a157e425SAlexander Motin bintime_mul(&tmp, ticks - 1); 813a157e425SAlexander Motin bintime_add(&state->nextevent, &tmp); 814bcb74c4cSAlexander Motin if (periodic || 815bcb74c4cSAlexander Motin bintime_cmp(&state->nextevent, &nexttick, >=)) { 816a157e425SAlexander Motin ET_HW_UNLOCK(state); 817a157e425SAlexander Motin return; 818a157e425SAlexander Motin } 819bcb74c4cSAlexander Motin } 820a157e425SAlexander Motin /* 821a157e425SAlexander Motin * Otherwise we have to wake that CPU up, as we can't get present 822a157e425SAlexander Motin * bintime to reprogram global timer from here. If timer is per-CPU, 823a157e425SAlexander Motin * we by definition can't do it from here. 824a157e425SAlexander Motin */ 825a157e425SAlexander Motin ET_HW_UNLOCK(state); 826a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) { 827a157e425SAlexander Motin state->handle = 1; 828a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 829a157e425SAlexander Motin } else { 830a157e425SAlexander Motin if (!cpu_idle_wakeup(cpu)) 831a157e425SAlexander Motin ipi_cpu(cpu, IPI_AST); 832a157e425SAlexander Motin } 833a157e425SAlexander Motin } 834a157e425SAlexander Motin #endif 835a157e425SAlexander Motin 836a157e425SAlexander Motin /* 837a157e425SAlexander Motin * Report or change the active event timers hardware. 838a157e425SAlexander Motin */ 83943fe7d45SAlexander Motin static int 840a157e425SAlexander Motin sysctl_kern_eventtimer_timer(SYSCTL_HANDLER_ARGS) 84143fe7d45SAlexander Motin { 84243fe7d45SAlexander Motin char buf[32]; 84343fe7d45SAlexander Motin struct eventtimer *et; 84443fe7d45SAlexander Motin int error; 84543fe7d45SAlexander Motin 84643fe7d45SAlexander Motin ET_LOCK(); 847a157e425SAlexander Motin et = timer; 84843fe7d45SAlexander Motin snprintf(buf, sizeof(buf), "%s", et->et_name); 84943fe7d45SAlexander Motin ET_UNLOCK(); 85043fe7d45SAlexander Motin error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 85143fe7d45SAlexander Motin ET_LOCK(); 852a157e425SAlexander Motin et = timer; 85343fe7d45SAlexander Motin if (error != 0 || req->newptr == NULL || 854a157e425SAlexander Motin strcasecmp(buf, et->et_name) == 0) { 85543fe7d45SAlexander Motin ET_UNLOCK(); 85643fe7d45SAlexander Motin return (error); 85743fe7d45SAlexander Motin } 858a157e425SAlexander Motin et = et_find(buf, 0, 0); 85943fe7d45SAlexander Motin if (et == NULL) { 86043fe7d45SAlexander Motin ET_UNLOCK(); 86143fe7d45SAlexander Motin return (ENOENT); 86243fe7d45SAlexander Motin } 86343fe7d45SAlexander Motin configtimer(0); 864a157e425SAlexander Motin et_free(timer); 865a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_C3STOP) 866a157e425SAlexander Motin cpu_disable_deep_sleep++; 867a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 868a157e425SAlexander Motin cpu_disable_deep_sleep--; 869afe41f2dSAlexander Motin periodic = want_periodic; 870a157e425SAlexander Motin timer = et; 871a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 87243fe7d45SAlexander Motin configtimer(1); 87343fe7d45SAlexander Motin ET_UNLOCK(); 87443fe7d45SAlexander Motin return (error); 87543fe7d45SAlexander Motin } 876a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer, 87743fe7d45SAlexander Motin CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 878dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_timer, "A", "Chosen event timer"); 879a157e425SAlexander Motin 880a157e425SAlexander Motin /* 881a157e425SAlexander Motin * Report or change the active event timer periodicity. 882a157e425SAlexander Motin */ 883a157e425SAlexander Motin static int 884a157e425SAlexander Motin sysctl_kern_eventtimer_periodic(SYSCTL_HANDLER_ARGS) 885a157e425SAlexander Motin { 886a157e425SAlexander Motin int error, val; 887a157e425SAlexander Motin 888a157e425SAlexander Motin val = periodic; 889a157e425SAlexander Motin error = sysctl_handle_int(oidp, &val, 0, req); 890a157e425SAlexander Motin if (error != 0 || req->newptr == NULL) 891a157e425SAlexander Motin return (error); 892a157e425SAlexander Motin ET_LOCK(); 893a157e425SAlexander Motin configtimer(0); 894afe41f2dSAlexander Motin periodic = want_periodic = val; 895a157e425SAlexander Motin configtimer(1); 896a157e425SAlexander Motin ET_UNLOCK(); 897a157e425SAlexander Motin return (error); 898a157e425SAlexander Motin } 899a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, periodic, 900a157e425SAlexander Motin CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 901dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_periodic, "I", "Enable event timer periodic mode"); 90243fe7d45SAlexander Motin 90343fe7d45SAlexander Motin #endif 904