143fe7d45SAlexander Motin /*- 28a36da99SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 38a36da99SPedro F. Giffuni * 45b999a6bSDavide Italiano * Copyright (c) 2010-2013 Alexander Motin <mav@FreeBSD.org> 543fe7d45SAlexander Motin * All rights reserved. 643fe7d45SAlexander Motin * 743fe7d45SAlexander Motin * Redistribution and use in source and binary forms, with or without 843fe7d45SAlexander Motin * modification, are permitted provided that the following conditions 943fe7d45SAlexander Motin * are met: 1043fe7d45SAlexander Motin * 1. Redistributions of source code must retain the above copyright 1143fe7d45SAlexander Motin * notice, this list of conditions and the following disclaimer, 1243fe7d45SAlexander Motin * without modification, immediately at the beginning of the file. 1343fe7d45SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright 1443fe7d45SAlexander Motin * notice, this list of conditions and the following disclaimer in the 1543fe7d45SAlexander Motin * documentation and/or other materials provided with the distribution. 1643fe7d45SAlexander Motin * 1743fe7d45SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1843fe7d45SAlexander Motin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1943fe7d45SAlexander Motin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2043fe7d45SAlexander Motin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2143fe7d45SAlexander Motin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2243fe7d45SAlexander Motin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2343fe7d45SAlexander Motin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2443fe7d45SAlexander Motin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2543fe7d45SAlexander Motin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2643fe7d45SAlexander Motin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2743fe7d45SAlexander Motin */ 2843fe7d45SAlexander Motin 2943fe7d45SAlexander Motin #include <sys/cdefs.h> 3043fe7d45SAlexander Motin __FBSDID("$FreeBSD$"); 3143fe7d45SAlexander Motin 3243fe7d45SAlexander Motin /* 3343fe7d45SAlexander Motin * Common routines to manage event timers hardware. 3443fe7d45SAlexander Motin */ 3543fe7d45SAlexander Motin 369dfc483cSAlexander Motin #include "opt_device_polling.h" 3743fe7d45SAlexander Motin 3843fe7d45SAlexander Motin #include <sys/param.h> 3943fe7d45SAlexander Motin #include <sys/systm.h> 4043fe7d45SAlexander Motin #include <sys/bus.h> 415b999a6bSDavide Italiano #include <sys/limits.h> 4243fe7d45SAlexander Motin #include <sys/lock.h> 4343fe7d45SAlexander Motin #include <sys/kdb.h> 44a157e425SAlexander Motin #include <sys/ktr.h> 4543fe7d45SAlexander Motin #include <sys/mutex.h> 4643fe7d45SAlexander Motin #include <sys/proc.h> 4743fe7d45SAlexander Motin #include <sys/kernel.h> 4843fe7d45SAlexander Motin #include <sys/sched.h> 4943fe7d45SAlexander Motin #include <sys/smp.h> 5043fe7d45SAlexander Motin #include <sys/sysctl.h> 5143fe7d45SAlexander Motin #include <sys/timeet.h> 520e189873SAlexander Motin #include <sys/timetc.h> 5343fe7d45SAlexander Motin 5443fe7d45SAlexander Motin #include <machine/atomic.h> 5543fe7d45SAlexander Motin #include <machine/clock.h> 5643fe7d45SAlexander Motin #include <machine/cpu.h> 5743fe7d45SAlexander Motin #include <machine/smp.h> 5843fe7d45SAlexander Motin 5992597e06SJohn Baldwin int cpu_disable_c2_sleep = 0; /* Timer dies in C2. */ 6092597e06SJohn Baldwin int cpu_disable_c3_sleep = 0; /* Timer dies in C3. */ 6143fe7d45SAlexander Motin 62a157e425SAlexander Motin static void setuptimer(void); 635b999a6bSDavide Italiano static void loadtimer(sbintime_t now, int first); 64a157e425SAlexander Motin static int doconfigtimer(void); 65a157e425SAlexander Motin static void configtimer(int start); 66a157e425SAlexander Motin static int round_freq(struct eventtimer *et, int freq); 6743fe7d45SAlexander Motin 685b999a6bSDavide Italiano static sbintime_t getnextcpuevent(int idle); 695b999a6bSDavide Italiano static sbintime_t getnextevent(void); 705b999a6bSDavide Italiano static int handleevents(sbintime_t now, int fake); 7143fe7d45SAlexander Motin 72a157e425SAlexander Motin static struct mtx et_hw_mtx; 73a157e425SAlexander Motin 74a157e425SAlexander Motin #define ET_HW_LOCK(state) \ 75a157e425SAlexander Motin { \ 76a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 77a157e425SAlexander Motin mtx_lock_spin(&(state)->et_hw_mtx); \ 78a157e425SAlexander Motin else \ 79a157e425SAlexander Motin mtx_lock_spin(&et_hw_mtx); \ 80a157e425SAlexander Motin } 81a157e425SAlexander Motin 82a157e425SAlexander Motin #define ET_HW_UNLOCK(state) \ 83a157e425SAlexander Motin { \ 84a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) \ 85a157e425SAlexander Motin mtx_unlock_spin(&(state)->et_hw_mtx); \ 86a157e425SAlexander Motin else \ 87a157e425SAlexander Motin mtx_unlock_spin(&et_hw_mtx); \ 88a157e425SAlexander Motin } 89a157e425SAlexander Motin 90a157e425SAlexander Motin static struct eventtimer *timer = NULL; 915b999a6bSDavide Italiano static sbintime_t timerperiod; /* Timer period for periodic mode. */ 925b999a6bSDavide Italiano static sbintime_t statperiod; /* statclock() events period. */ 935b999a6bSDavide Italiano static sbintime_t profperiod; /* profclock() events period. */ 945b999a6bSDavide Italiano static sbintime_t nexttick; /* Next global timer tick time. */ 955b999a6bSDavide Italiano static u_int busy = 1; /* Reconfiguration is in progress. */ 96af3b2549SHans Petter Selasky static int profiling; /* Profiling events enabled. */ 97a157e425SAlexander Motin 98a157e425SAlexander Motin static char timername[32]; /* Wanted timer. */ 99a157e425SAlexander Motin TUNABLE_STR("kern.eventtimer.timer", timername, sizeof(timername)); 100a157e425SAlexander Motin 101af3b2549SHans Petter Selasky static int singlemul; /* Multiplier for periodic mode. */ 102af3b2549SHans Petter Selasky SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RWTUN, &singlemul, 103a157e425SAlexander Motin 0, "Multiplier for periodic mode"); 10443fe7d45SAlexander Motin 105af3b2549SHans Petter Selasky static u_int idletick; /* Run periodic events when idle. */ 106af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RWTUN, &idletick, 107a157e425SAlexander Motin 0, "Run periodic events when idle"); 108a157e425SAlexander Motin 109af3b2549SHans Petter Selasky static int periodic; /* Periodic or one-shot mode. */ 110af3b2549SHans Petter Selasky static int want_periodic; /* What mode to prefer. */ 111afe41f2dSAlexander Motin TUNABLE_INT("kern.eventtimer.periodic", &want_periodic); 112a157e425SAlexander Motin 113a157e425SAlexander Motin struct pcpu_state { 114a157e425SAlexander Motin struct mtx et_hw_mtx; /* Per-CPU timer mutex. */ 115a157e425SAlexander Motin u_int action; /* Reconfiguration requests. */ 116a157e425SAlexander Motin u_int handle; /* Immediate handle resuests. */ 1175b999a6bSDavide Italiano sbintime_t now; /* Last tick time. */ 1185b999a6bSDavide Italiano sbintime_t nextevent; /* Next scheduled event on this CPU. */ 1195b999a6bSDavide Italiano sbintime_t nexttick; /* Next timer tick time. */ 120d3e2e28eSAlexander Motin sbintime_t nexthard; /* Next hardclock() event. */ 1215b999a6bSDavide Italiano sbintime_t nextstat; /* Next statclock() event. */ 1225b999a6bSDavide Italiano sbintime_t nextprof; /* Next profclock() event. */ 1235b999a6bSDavide Italiano sbintime_t nextcall; /* Next callout event. */ 1245b999a6bSDavide Italiano sbintime_t nextcallopt; /* Next optional callout event. */ 125a157e425SAlexander Motin int ipi; /* This CPU needs IPI. */ 126a157e425SAlexander Motin int idle; /* This CPU is in idle mode. */ 127a157e425SAlexander Motin }; 128a157e425SAlexander Motin 1292bf95012SAndrew Turner DPCPU_DEFINE_STATIC(struct pcpu_state, timerstate); 1305b999a6bSDavide Italiano DPCPU_DEFINE(sbintime_t, hardclocktime); 131fdc5dd2dSAlexander Motin 132a157e425SAlexander Motin /* 133a157e425SAlexander Motin * Timer broadcast IPI handler. 134a157e425SAlexander Motin */ 135a157e425SAlexander Motin int 136a157e425SAlexander Motin hardclockintr(void) 13743fe7d45SAlexander Motin { 1385b999a6bSDavide Italiano sbintime_t now; 139a157e425SAlexander Motin struct pcpu_state *state; 140a157e425SAlexander Motin int done; 14143fe7d45SAlexander Motin 142a157e425SAlexander Motin if (doconfigtimer() || busy) 143a157e425SAlexander Motin return (FILTER_HANDLED); 144a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 145a157e425SAlexander Motin now = state->now; 1465b999a6bSDavide Italiano CTR3(KTR_SPARE2, "ipi at %d: now %d.%08x", 1475b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 1485b999a6bSDavide Italiano done = handleevents(now, 0); 149a157e425SAlexander Motin return (done ? FILTER_HANDLED : FILTER_STRAY); 150a157e425SAlexander Motin } 151a157e425SAlexander Motin 152a157e425SAlexander Motin /* 153a157e425SAlexander Motin * Handle all events for specified time on this CPU 154a157e425SAlexander Motin */ 155a157e425SAlexander Motin static int 1565b999a6bSDavide Italiano handleevents(sbintime_t now, int fake) 157a157e425SAlexander Motin { 1585b999a6bSDavide Italiano sbintime_t t, *hct; 159a157e425SAlexander Motin struct trapframe *frame; 160a157e425SAlexander Motin struct pcpu_state *state; 161a157e425SAlexander Motin int usermode; 162a157e425SAlexander Motin int done, runs; 163a157e425SAlexander Motin 1645b999a6bSDavide Italiano CTR3(KTR_SPARE2, "handle at %d: now %d.%08x", 1655b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 166a157e425SAlexander Motin done = 0; 167a157e425SAlexander Motin if (fake) { 168a157e425SAlexander Motin frame = NULL; 169a157e425SAlexander Motin usermode = 0; 170a157e425SAlexander Motin } else { 171a157e425SAlexander Motin frame = curthread->td_intr_frame; 172a157e425SAlexander Motin usermode = TRAPF_USERMODE(frame); 173a157e425SAlexander Motin } 174dd7498aeSAndriy Gapon 175a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 176dd7498aeSAndriy Gapon 177bcfd016cSAlexander Motin runs = 0; 1785b999a6bSDavide Italiano while (now >= state->nexthard) { 1795b999a6bSDavide Italiano state->nexthard += tick_sbt; 180a157e425SAlexander Motin runs++; 18143fe7d45SAlexander Motin } 182c0722d20SAlexander Motin if (runs) { 1835b999a6bSDavide Italiano hct = DPCPU_PTR(hardclocktime); 1845b999a6bSDavide Italiano *hct = state->nexthard - tick_sbt; 185c0722d20SAlexander Motin if (fake < 2) { 186*cc4f3d0aSMark Johnston hardclock(runs, usermode); 187a157e425SAlexander Motin done = 1; 18843fe7d45SAlexander Motin } 189c0722d20SAlexander Motin } 190bcfd016cSAlexander Motin runs = 0; 1915b999a6bSDavide Italiano while (now >= state->nextstat) { 1925b999a6bSDavide Italiano state->nextstat += statperiod; 193bcfd016cSAlexander Motin runs++; 194bcfd016cSAlexander Motin } 195bcfd016cSAlexander Motin if (runs && fake < 2) { 196*cc4f3d0aSMark Johnston statclock(runs, usermode); 197a157e425SAlexander Motin done = 1; 19843fe7d45SAlexander Motin } 199a157e425SAlexander Motin if (profiling) { 200bcfd016cSAlexander Motin runs = 0; 2015b999a6bSDavide Italiano while (now >= state->nextprof) { 2025b999a6bSDavide Italiano state->nextprof += profperiod; 203bcfd016cSAlexander Motin runs++; 204bcfd016cSAlexander Motin } 205bcfd016cSAlexander Motin if (runs && !fake) { 206*cc4f3d0aSMark Johnston profclock(runs, usermode, TRAPF_PC(frame)); 207a157e425SAlexander Motin done = 1; 20843fe7d45SAlexander Motin } 209a157e425SAlexander Motin } else 210a157e425SAlexander Motin state->nextprof = state->nextstat; 21110c87557SHans Petter Selasky if (now >= state->nextcallopt || now >= state->nextcall) { 2124bc38a5aSDavide Italiano state->nextcall = state->nextcallopt = SBT_MAX; 2135b999a6bSDavide Italiano callout_process(now); 2145b999a6bSDavide Italiano } 215dd7498aeSAndriy Gapon 2165b999a6bSDavide Italiano t = getnextcpuevent(0); 217a157e425SAlexander Motin ET_HW_LOCK(state); 218a157e425SAlexander Motin if (!busy) { 219a157e425SAlexander Motin state->idle = 0; 220a157e425SAlexander Motin state->nextevent = t; 221e37e08c7SAlexander Motin loadtimer(now, (fake == 2) && 222e37e08c7SAlexander Motin (timer->et_flags & ET_FLAGS_PERCPU)); 22343fe7d45SAlexander Motin } 224a157e425SAlexander Motin ET_HW_UNLOCK(state); 225a157e425SAlexander Motin return (done); 22643fe7d45SAlexander Motin } 22743fe7d45SAlexander Motin 22843fe7d45SAlexander Motin /* 229a157e425SAlexander Motin * Schedule binuptime of the next event on current CPU. 23043fe7d45SAlexander Motin */ 2315b999a6bSDavide Italiano static sbintime_t 2325b999a6bSDavide Italiano getnextcpuevent(int idle) 23343fe7d45SAlexander Motin { 2345b999a6bSDavide Italiano sbintime_t event; 235a157e425SAlexander Motin struct pcpu_state *state; 2365b999a6bSDavide Italiano u_int hardfreq; 23743fe7d45SAlexander Motin 238a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 2395b999a6bSDavide Italiano /* Handle hardclock() events, skipping some if CPU is idle. */ 2405b999a6bSDavide Italiano event = state->nexthard; 2415b999a6bSDavide Italiano if (idle) { 2425b999a6bSDavide Italiano hardfreq = (u_int)hz / 2; 2435b999a6bSDavide Italiano if (tc_min_ticktock_freq > 2 2445b999a6bSDavide Italiano #ifdef SMP 2455b999a6bSDavide Italiano && curcpu == CPU_FIRST() 2465b999a6bSDavide Italiano #endif 2475b999a6bSDavide Italiano ) 2485b999a6bSDavide Italiano hardfreq = hz / tc_min_ticktock_freq; 2495b999a6bSDavide Italiano if (hardfreq > 1) 2505b999a6bSDavide Italiano event += tick_sbt * (hardfreq - 1); 251fd053faeSAlexander Motin } 2525b999a6bSDavide Italiano /* Handle callout events. */ 2535b999a6bSDavide Italiano if (event > state->nextcall) 2545b999a6bSDavide Italiano event = state->nextcall; 255fd053faeSAlexander Motin if (!idle) { /* If CPU is active - handle other types of events. */ 2565b999a6bSDavide Italiano if (event > state->nextstat) 2575b999a6bSDavide Italiano event = state->nextstat; 2585b999a6bSDavide Italiano if (profiling && event > state->nextprof) 2595b999a6bSDavide Italiano event = state->nextprof; 26043fe7d45SAlexander Motin } 2615b999a6bSDavide Italiano return (event); 26243fe7d45SAlexander Motin } 263a157e425SAlexander Motin 264a157e425SAlexander Motin /* 265a157e425SAlexander Motin * Schedule binuptime of the next event on all CPUs. 266a157e425SAlexander Motin */ 2675b999a6bSDavide Italiano static sbintime_t 2685b999a6bSDavide Italiano getnextevent(void) 269a157e425SAlexander Motin { 270a157e425SAlexander Motin struct pcpu_state *state; 2715b999a6bSDavide Italiano sbintime_t event; 272a157e425SAlexander Motin #ifdef SMP 273a157e425SAlexander Motin int cpu; 274a157e425SAlexander Motin #endif 2755cc2d25aSMatt Macy #ifdef KTR 2765b999a6bSDavide Italiano int c; 277a157e425SAlexander Motin 2785cc2d25aSMatt Macy c = -1; 2795cc2d25aSMatt Macy #endif 280a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 2815b999a6bSDavide Italiano event = state->nextevent; 282fd053faeSAlexander Motin #ifdef SMP 2835b999a6bSDavide Italiano if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) { 284a157e425SAlexander Motin CPU_FOREACH(cpu) { 285a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 2865b999a6bSDavide Italiano if (event > state->nextevent) { 2875b999a6bSDavide Italiano event = state->nextevent; 2885cc2d25aSMatt Macy #ifdef KTR 289a157e425SAlexander Motin c = cpu; 2905cc2d25aSMatt Macy #endif 29143fe7d45SAlexander Motin } 29243fe7d45SAlexander Motin } 2932d7d1642SGrzegorz Bernacki } 294a157e425SAlexander Motin #endif 2955b999a6bSDavide Italiano CTR4(KTR_SPARE2, "next at %d: next %d.%08x by %d", 2965b999a6bSDavide Italiano curcpu, (int)(event >> 32), (u_int)(event & 0xffffffff), c); 2975b999a6bSDavide Italiano return (event); 298a157e425SAlexander Motin } 299a157e425SAlexander Motin 300a157e425SAlexander Motin /* Hardware timer callback function. */ 301a157e425SAlexander Motin static void 302a157e425SAlexander Motin timercb(struct eventtimer *et, void *arg) 303a157e425SAlexander Motin { 3045b999a6bSDavide Italiano sbintime_t now; 3055b999a6bSDavide Italiano sbintime_t *next; 306a157e425SAlexander Motin struct pcpu_state *state; 307a157e425SAlexander Motin #ifdef SMP 308a157e425SAlexander Motin int cpu, bcast; 309a157e425SAlexander Motin #endif 310a157e425SAlexander Motin 311a157e425SAlexander Motin /* Do not touch anything if somebody reconfiguring timers. */ 312a157e425SAlexander Motin if (busy) 313a157e425SAlexander Motin return; 314a157e425SAlexander Motin /* Update present and next tick times. */ 315a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 316a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_PERCPU) { 317a157e425SAlexander Motin next = &state->nexttick; 318a157e425SAlexander Motin } else 319a157e425SAlexander Motin next = &nexttick; 3205b999a6bSDavide Italiano now = sbinuptime(); 3215b999a6bSDavide Italiano if (periodic) 3225b999a6bSDavide Italiano *next = now + timerperiod; 3235b999a6bSDavide Italiano else 3245b999a6bSDavide Italiano *next = -1; /* Next tick is not scheduled yet. */ 325a157e425SAlexander Motin state->now = now; 3265b999a6bSDavide Italiano CTR3(KTR_SPARE2, "intr at %d: now %d.%08x", 3275b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 328a157e425SAlexander Motin 329a157e425SAlexander Motin #ifdef SMP 330fdce57a0SJohn Baldwin #ifdef EARLY_AP_STARTUP 331fdce57a0SJohn Baldwin MPASS(mp_ncpus == 1 || smp_started); 332fdce57a0SJohn Baldwin #endif 333a157e425SAlexander Motin /* Prepare broadcasting to other CPUs for non-per-CPU timers. */ 334a157e425SAlexander Motin bcast = 0; 335fdce57a0SJohn Baldwin #ifdef EARLY_AP_STARTUP 336fdce57a0SJohn Baldwin if ((et->et_flags & ET_FLAGS_PERCPU) == 0) { 337fdce57a0SJohn Baldwin #else 338a157e425SAlexander Motin if ((et->et_flags & ET_FLAGS_PERCPU) == 0 && smp_started) { 339fdce57a0SJohn Baldwin #endif 340a157e425SAlexander Motin CPU_FOREACH(cpu) { 341a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 342a157e425SAlexander Motin ET_HW_LOCK(state); 343a157e425SAlexander Motin state->now = now; 3445b999a6bSDavide Italiano if (now >= state->nextevent) { 3455b999a6bSDavide Italiano state->nextevent += SBT_1S; 3468e860de4SAlexander Motin if (curcpu != cpu) { 347a157e425SAlexander Motin state->ipi = 1; 348a157e425SAlexander Motin bcast = 1; 349a157e425SAlexander Motin } 3508e860de4SAlexander Motin } 351a157e425SAlexander Motin ET_HW_UNLOCK(state); 352a157e425SAlexander Motin } 353a157e425SAlexander Motin } 354a157e425SAlexander Motin #endif 355a157e425SAlexander Motin 356a157e425SAlexander Motin /* Handle events for this time on this CPU. */ 3575b999a6bSDavide Italiano handleevents(now, 0); 358a157e425SAlexander Motin 359a157e425SAlexander Motin #ifdef SMP 360a157e425SAlexander Motin /* Broadcast interrupt to other CPUs for non-per-CPU timers. */ 361a157e425SAlexander Motin if (bcast) { 362a157e425SAlexander Motin CPU_FOREACH(cpu) { 363a157e425SAlexander Motin if (curcpu == cpu) 364a157e425SAlexander Motin continue; 365a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 366a157e425SAlexander Motin if (state->ipi) { 367a157e425SAlexander Motin state->ipi = 0; 368a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 369a157e425SAlexander Motin } 370a157e425SAlexander Motin } 371a157e425SAlexander Motin } 372a157e425SAlexander Motin #endif 373a157e425SAlexander Motin } 374a157e425SAlexander Motin 375a157e425SAlexander Motin /* 376a157e425SAlexander Motin * Load new value into hardware timer. 377a157e425SAlexander Motin */ 378a157e425SAlexander Motin static void 3795b999a6bSDavide Italiano loadtimer(sbintime_t now, int start) 380a157e425SAlexander Motin { 381a157e425SAlexander Motin struct pcpu_state *state; 3825b999a6bSDavide Italiano sbintime_t new; 3835b999a6bSDavide Italiano sbintime_t *next; 384a157e425SAlexander Motin uint64_t tmp; 385a157e425SAlexander Motin int eq; 386a157e425SAlexander Motin 387c70410e6SAlexander Motin if (timer->et_flags & ET_FLAGS_PERCPU) { 388c70410e6SAlexander Motin state = DPCPU_PTR(timerstate); 389c70410e6SAlexander Motin next = &state->nexttick; 390c70410e6SAlexander Motin } else 391c70410e6SAlexander Motin next = &nexttick; 392a157e425SAlexander Motin if (periodic) { 393a157e425SAlexander Motin if (start) { 394a157e425SAlexander Motin /* 395a157e425SAlexander Motin * Try to start all periodic timers aligned 396a157e425SAlexander Motin * to period to make events synchronous. 397a157e425SAlexander Motin */ 3985b999a6bSDavide Italiano tmp = now % timerperiod; 3995b999a6bSDavide Italiano new = timerperiod - tmp; 4005b999a6bSDavide Italiano if (new < tmp) /* Left less then passed. */ 4015b999a6bSDavide Italiano new += timerperiod; 402a157e425SAlexander Motin CTR5(KTR_SPARE2, "load p at %d: now %d.%08x first in %d.%08x", 4035b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff), 4045b999a6bSDavide Italiano (int)(new >> 32), (u_int)(new & 0xffffffff)); 4055b999a6bSDavide Italiano *next = new + now; 4065b999a6bSDavide Italiano et_start(timer, new, timerperiod); 407a157e425SAlexander Motin } 408a157e425SAlexander Motin } else { 4095b999a6bSDavide Italiano new = getnextevent(); 4105b999a6bSDavide Italiano eq = (new == *next); 4115b999a6bSDavide Italiano CTR4(KTR_SPARE2, "load at %d: next %d.%08x eq %d", 4125b999a6bSDavide Italiano curcpu, (int)(new >> 32), (u_int)(new & 0xffffffff), eq); 413a157e425SAlexander Motin if (!eq) { 414a157e425SAlexander Motin *next = new; 4155b999a6bSDavide Italiano et_start(timer, new - now, 0); 416a157e425SAlexander Motin } 417a157e425SAlexander Motin } 418a157e425SAlexander Motin } 419a157e425SAlexander Motin 420a157e425SAlexander Motin /* 421a157e425SAlexander Motin * Prepare event timer parameters after configuration changes. 422a157e425SAlexander Motin */ 423a157e425SAlexander Motin static void 424a157e425SAlexander Motin setuptimer(void) 425a157e425SAlexander Motin { 426a157e425SAlexander Motin int freq; 427a157e425SAlexander Motin 428a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 429a157e425SAlexander Motin periodic = 0; 430a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 431a157e425SAlexander Motin periodic = 1; 432dd9595e7SAlexander Motin singlemul = MIN(MAX(singlemul, 1), 20); 433a157e425SAlexander Motin freq = hz * singlemul; 434a157e425SAlexander Motin while (freq < (profiling ? profhz : stathz)) 435a157e425SAlexander Motin freq += hz; 436a157e425SAlexander Motin freq = round_freq(timer, freq); 4375b999a6bSDavide Italiano timerperiod = SBT_1S / freq; 438a157e425SAlexander Motin } 43943fe7d45SAlexander Motin 44043fe7d45SAlexander Motin /* 44143fe7d45SAlexander Motin * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler. 44243fe7d45SAlexander Motin */ 443a157e425SAlexander Motin static int 444a157e425SAlexander Motin doconfigtimer(void) 44543fe7d45SAlexander Motin { 4465b999a6bSDavide Italiano sbintime_t now; 447a157e425SAlexander Motin struct pcpu_state *state; 44843fe7d45SAlexander Motin 449a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 450a157e425SAlexander Motin switch (atomic_load_acq_int(&state->action)) { 451a157e425SAlexander Motin case 1: 4525b999a6bSDavide Italiano now = sbinuptime(); 453a157e425SAlexander Motin ET_HW_LOCK(state); 4545b999a6bSDavide Italiano loadtimer(now, 1); 455a157e425SAlexander Motin ET_HW_UNLOCK(state); 456a157e425SAlexander Motin state->handle = 0; 457a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 458a157e425SAlexander Motin return (1); 459a157e425SAlexander Motin case 2: 460a157e425SAlexander Motin ET_HW_LOCK(state); 461a157e425SAlexander Motin et_stop(timer); 462a157e425SAlexander Motin ET_HW_UNLOCK(state); 463a157e425SAlexander Motin state->handle = 0; 464a157e425SAlexander Motin atomic_store_rel_int(&state->action, 0); 465a157e425SAlexander Motin return (1); 466a157e425SAlexander Motin } 467a157e425SAlexander Motin if (atomic_readandclear_int(&state->handle) && !busy) { 4685b999a6bSDavide Italiano now = sbinuptime(); 4695b999a6bSDavide Italiano handleevents(now, 0); 47043fe7d45SAlexander Motin return (1); 47143fe7d45SAlexander Motin } 47243fe7d45SAlexander Motin return (0); 47343fe7d45SAlexander Motin } 47443fe7d45SAlexander Motin 47543fe7d45SAlexander Motin /* 47643fe7d45SAlexander Motin * Reconfigure specified timer. 47743fe7d45SAlexander Motin * For per-CPU timers use IPI to make other CPUs to reconfigure. 47843fe7d45SAlexander Motin */ 47943fe7d45SAlexander Motin static void 480a157e425SAlexander Motin configtimer(int start) 48143fe7d45SAlexander Motin { 4825b999a6bSDavide Italiano sbintime_t now, next; 483a157e425SAlexander Motin struct pcpu_state *state; 48443fe7d45SAlexander Motin int cpu; 48543fe7d45SAlexander Motin 486a157e425SAlexander Motin if (start) { 487a157e425SAlexander Motin setuptimer(); 4885b999a6bSDavide Italiano now = sbinuptime(); 4895b999a6bSDavide Italiano } else 4905b999a6bSDavide Italiano now = 0; 49143fe7d45SAlexander Motin critical_enter(); 492a157e425SAlexander Motin ET_HW_LOCK(DPCPU_PTR(timerstate)); 493a157e425SAlexander Motin if (start) { 494a157e425SAlexander Motin /* Initialize time machine parameters. */ 4955b999a6bSDavide Italiano next = now + timerperiod; 496a157e425SAlexander Motin if (periodic) 497a157e425SAlexander Motin nexttick = next; 49843fe7d45SAlexander Motin else 4995b999a6bSDavide Italiano nexttick = -1; 500fdce57a0SJohn Baldwin #ifdef EARLY_AP_STARTUP 501fdce57a0SJohn Baldwin MPASS(mp_ncpus == 1 || smp_started); 502fdce57a0SJohn Baldwin #endif 503a157e425SAlexander Motin CPU_FOREACH(cpu) { 504a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 505a157e425SAlexander Motin state->now = now; 506fdce57a0SJohn Baldwin #ifndef EARLY_AP_STARTUP 5075b999a6bSDavide Italiano if (!smp_started && cpu != CPU_FIRST()) 5084bc38a5aSDavide Italiano state->nextevent = SBT_MAX; 5095b999a6bSDavide Italiano else 510fdce57a0SJohn Baldwin #endif 511a157e425SAlexander Motin state->nextevent = next; 512a157e425SAlexander Motin if (periodic) 513a157e425SAlexander Motin state->nexttick = next; 514a157e425SAlexander Motin else 5155b999a6bSDavide Italiano state->nexttick = -1; 516a157e425SAlexander Motin state->nexthard = next; 517a157e425SAlexander Motin state->nextstat = next; 518a157e425SAlexander Motin state->nextprof = next; 5195b999a6bSDavide Italiano state->nextcall = next; 5205b999a6bSDavide Italiano state->nextcallopt = next; 521a157e425SAlexander Motin hardclock_sync(cpu); 522a157e425SAlexander Motin } 523a157e425SAlexander Motin busy = 0; 524a157e425SAlexander Motin /* Start global timer or per-CPU timer of this CPU. */ 5255b999a6bSDavide Italiano 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 533fdce57a0SJohn Baldwin #ifdef EARLY_AP_STARTUP 534fdce57a0SJohn Baldwin /* If timer is global we are done. */ 535fdce57a0SJohn Baldwin if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) { 536fdce57a0SJohn Baldwin #else 537a157e425SAlexander Motin /* If timer is global or there is no other CPUs yet - we are done. */ 538a157e425SAlexander Motin if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) { 539fdce57a0SJohn Baldwin #endif 54043fe7d45SAlexander Motin critical_exit(); 54143fe7d45SAlexander Motin return; 54243fe7d45SAlexander Motin } 54343fe7d45SAlexander Motin /* Set reconfigure flags for other CPUs. */ 54443fe7d45SAlexander Motin CPU_FOREACH(cpu) { 545a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 546a157e425SAlexander Motin atomic_store_rel_int(&state->action, 547a157e425SAlexander Motin (cpu == curcpu) ? 0 : ( start ? 1 : 2)); 54843fe7d45SAlexander Motin } 549a157e425SAlexander Motin /* Broadcast reconfigure IPI. */ 550a157e425SAlexander Motin ipi_all_but_self(IPI_HARDCLOCK); 55143fe7d45SAlexander Motin /* Wait for reconfiguration completed. */ 55243fe7d45SAlexander Motin restart: 55343fe7d45SAlexander Motin cpu_spinwait(); 55443fe7d45SAlexander Motin CPU_FOREACH(cpu) { 55543fe7d45SAlexander Motin if (cpu == curcpu) 55643fe7d45SAlexander Motin continue; 557a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 558a157e425SAlexander Motin if (atomic_load_acq_int(&state->action)) 55943fe7d45SAlexander Motin goto restart; 56043fe7d45SAlexander Motin } 56143fe7d45SAlexander Motin #endif 562a157e425SAlexander Motin critical_exit(); 56343fe7d45SAlexander Motin } 56443fe7d45SAlexander Motin 565a157e425SAlexander Motin /* 566a157e425SAlexander Motin * Calculate nearest frequency supported by hardware timer. 567a157e425SAlexander Motin */ 56851636352SAlexander Motin static int 56951636352SAlexander Motin round_freq(struct eventtimer *et, int freq) 57051636352SAlexander Motin { 57151636352SAlexander Motin uint64_t div; 57251636352SAlexander Motin 57351636352SAlexander Motin if (et->et_frequency != 0) { 574599cf0f1SAlexander Motin div = lmax((et->et_frequency + freq / 2) / freq, 1); 57551636352SAlexander Motin if (et->et_flags & ET_FLAGS_POW2DIV) 57651636352SAlexander Motin div = 1 << (flsl(div + div / 2) - 1); 57751636352SAlexander Motin freq = (et->et_frequency + div / 2) / div; 57851636352SAlexander Motin } 579fdc5dd2dSAlexander Motin if (et->et_min_period > SBT_1S) 580803a9b3eSAlexander Motin panic("Event timer \"%s\" doesn't support sub-second periods!", 581803a9b3eSAlexander Motin et->et_name); 582fdc5dd2dSAlexander Motin else if (et->et_min_period != 0) 583fdc5dd2dSAlexander Motin freq = min(freq, SBT2FREQ(et->et_min_period)); 584fdc5dd2dSAlexander Motin if (et->et_max_period < SBT_1S && et->et_max_period != 0) 585fdc5dd2dSAlexander Motin freq = max(freq, SBT2FREQ(et->et_max_period)); 58651636352SAlexander Motin return (freq); 58751636352SAlexander Motin } 58851636352SAlexander Motin 58943fe7d45SAlexander Motin /* 590a157e425SAlexander Motin * Configure and start event timers (BSP part). 59143fe7d45SAlexander Motin */ 59243fe7d45SAlexander Motin void 59343fe7d45SAlexander Motin cpu_initclocks_bsp(void) 59443fe7d45SAlexander Motin { 595a157e425SAlexander Motin struct pcpu_state *state; 596a157e425SAlexander Motin int base, div, cpu; 59743fe7d45SAlexander Motin 598a157e425SAlexander Motin mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 599a157e425SAlexander Motin CPU_FOREACH(cpu) { 600a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 601a157e425SAlexander Motin mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 6024bc38a5aSDavide Italiano state->nextcall = SBT_MAX; 6034bc38a5aSDavide Italiano state->nextcallopt = SBT_MAX; 604a157e425SAlexander Motin } 605afe41f2dSAlexander Motin periodic = want_periodic; 606a157e425SAlexander Motin /* Grab requested timer or the best of present. */ 607a157e425SAlexander Motin if (timername[0]) 608a157e425SAlexander Motin timer = et_find(timername, 0, 0); 609a157e425SAlexander Motin if (timer == NULL && periodic) { 610a157e425SAlexander Motin timer = et_find(NULL, 61143fe7d45SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 612a157e425SAlexander Motin } 613a157e425SAlexander Motin if (timer == NULL) { 614a157e425SAlexander Motin timer = et_find(NULL, 615a157e425SAlexander Motin ET_FLAGS_ONESHOT, ET_FLAGS_ONESHOT); 616a157e425SAlexander Motin } 617a157e425SAlexander Motin if (timer == NULL && !periodic) { 618a157e425SAlexander Motin timer = et_find(NULL, 619a157e425SAlexander Motin ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 620a157e425SAlexander Motin } 621a157e425SAlexander Motin if (timer == NULL) 622a157e425SAlexander Motin panic("No usable event timer found!"); 623a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 624a157e425SAlexander Motin 625a157e425SAlexander Motin /* Adapt to timer capabilities. */ 626a157e425SAlexander Motin if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 627a157e425SAlexander Motin periodic = 0; 628a157e425SAlexander Motin else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 629a157e425SAlexander Motin periodic = 1; 630a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 63192597e06SJohn Baldwin cpu_disable_c3_sleep++; 632a157e425SAlexander Motin 63343fe7d45SAlexander Motin /* 63443fe7d45SAlexander Motin * We honor the requested 'hz' value. 63543fe7d45SAlexander Motin * We want to run stathz in the neighborhood of 128hz. 63643fe7d45SAlexander Motin * We would like profhz to run as often as possible. 63743fe7d45SAlexander Motin */ 638dd9595e7SAlexander Motin if (singlemul <= 0 || singlemul > 20) { 63943fe7d45SAlexander Motin if (hz >= 1500 || (hz % 128) == 0) 64043fe7d45SAlexander Motin singlemul = 1; 64143fe7d45SAlexander Motin else if (hz >= 750) 64243fe7d45SAlexander Motin singlemul = 2; 64343fe7d45SAlexander Motin else 64443fe7d45SAlexander Motin singlemul = 4; 64543fe7d45SAlexander Motin } 646a157e425SAlexander Motin if (periodic) { 647a157e425SAlexander Motin base = round_freq(timer, hz * singlemul); 64851636352SAlexander Motin singlemul = max((base + hz / 2) / hz, 1); 64951636352SAlexander Motin hz = (base + singlemul / 2) / singlemul; 65051636352SAlexander Motin if (base <= 128) 65143fe7d45SAlexander Motin stathz = base; 65243fe7d45SAlexander Motin else { 65343fe7d45SAlexander Motin div = base / 128; 65451636352SAlexander Motin if (div >= singlemul && (div % singlemul) == 0) 65543fe7d45SAlexander Motin div++; 65643fe7d45SAlexander Motin stathz = base / div; 65743fe7d45SAlexander Motin } 65843fe7d45SAlexander Motin profhz = stathz; 65951636352SAlexander Motin while ((profhz + stathz) <= 128 * 64) 66043fe7d45SAlexander Motin profhz += stathz; 661a157e425SAlexander Motin profhz = round_freq(timer, profhz); 66243fe7d45SAlexander Motin } else { 663a157e425SAlexander Motin hz = round_freq(timer, hz); 664a157e425SAlexander Motin stathz = round_freq(timer, 127); 665a157e425SAlexander Motin profhz = round_freq(timer, stathz * 64); 66643fe7d45SAlexander Motin } 667599cf0f1SAlexander Motin tick = 1000000 / hz; 6685b999a6bSDavide Italiano tick_sbt = SBT_1S / hz; 6695b999a6bSDavide Italiano tick_bt = sbttobt(tick_sbt); 6705b999a6bSDavide Italiano statperiod = SBT_1S / stathz; 6715b999a6bSDavide Italiano profperiod = SBT_1S / profhz; 67243fe7d45SAlexander Motin ET_LOCK(); 673a157e425SAlexander Motin configtimer(1); 67443fe7d45SAlexander Motin ET_UNLOCK(); 67543fe7d45SAlexander Motin } 67643fe7d45SAlexander Motin 677a157e425SAlexander Motin /* 678a157e425SAlexander Motin * Start per-CPU event timers on APs. 679a157e425SAlexander Motin */ 68043fe7d45SAlexander Motin void 68143fe7d45SAlexander Motin cpu_initclocks_ap(void) 68243fe7d45SAlexander Motin { 6835b999a6bSDavide Italiano sbintime_t now; 684a157e425SAlexander Motin struct pcpu_state *state; 6855b999a6bSDavide Italiano struct thread *td; 68643fe7d45SAlexander Motin 687a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 6885b999a6bSDavide Italiano now = sbinuptime(); 689a157e425SAlexander Motin ET_HW_LOCK(state); 690c70410e6SAlexander Motin state->now = now; 691c70410e6SAlexander Motin hardclock_sync(curcpu); 6925b999a6bSDavide Italiano spinlock_enter(); 693a157e425SAlexander Motin ET_HW_UNLOCK(state); 6945b999a6bSDavide Italiano td = curthread; 6955b999a6bSDavide Italiano td->td_intr_nesting_level++; 6965b999a6bSDavide Italiano handleevents(state->now, 2); 6975b999a6bSDavide Italiano td->td_intr_nesting_level--; 6985b999a6bSDavide Italiano spinlock_exit(); 69943fe7d45SAlexander Motin } 70043fe7d45SAlexander Motin 70127dca831SAndriy Gapon void 70227dca831SAndriy Gapon suspendclock(void) 70327dca831SAndriy Gapon { 70427dca831SAndriy Gapon ET_LOCK(); 70527dca831SAndriy Gapon configtimer(0); 70627dca831SAndriy Gapon ET_UNLOCK(); 70727dca831SAndriy Gapon } 70827dca831SAndriy Gapon 70927dca831SAndriy Gapon void 71027dca831SAndriy Gapon resumeclock(void) 71127dca831SAndriy Gapon { 71227dca831SAndriy Gapon ET_LOCK(); 71327dca831SAndriy Gapon configtimer(1); 71427dca831SAndriy Gapon ET_UNLOCK(); 71527dca831SAndriy Gapon } 71627dca831SAndriy Gapon 717a157e425SAlexander Motin /* 718a157e425SAlexander Motin * Switch to profiling clock rates. 719a157e425SAlexander Motin */ 72043fe7d45SAlexander Motin void 72143fe7d45SAlexander Motin cpu_startprofclock(void) 72243fe7d45SAlexander Motin { 72343fe7d45SAlexander Motin 72443fe7d45SAlexander Motin ET_LOCK(); 7251af19ee4SAlexander Motin if (profiling == 0) { 726a157e425SAlexander Motin if (periodic) { 727a157e425SAlexander Motin configtimer(0); 728a157e425SAlexander Motin profiling = 1; 729a157e425SAlexander Motin configtimer(1); 730a157e425SAlexander Motin } else 731a157e425SAlexander Motin profiling = 1; 7321af19ee4SAlexander Motin } else 7331af19ee4SAlexander Motin profiling++; 73443fe7d45SAlexander Motin ET_UNLOCK(); 73543fe7d45SAlexander Motin } 73643fe7d45SAlexander Motin 737a157e425SAlexander Motin /* 738a157e425SAlexander Motin * Switch to regular clock rates. 739a157e425SAlexander Motin */ 74043fe7d45SAlexander Motin void 74143fe7d45SAlexander Motin cpu_stopprofclock(void) 74243fe7d45SAlexander Motin { 74343fe7d45SAlexander Motin 74443fe7d45SAlexander Motin ET_LOCK(); 7451af19ee4SAlexander Motin if (profiling == 1) { 746a157e425SAlexander Motin if (periodic) { 747a157e425SAlexander Motin configtimer(0); 748a157e425SAlexander Motin profiling = 0; 749a157e425SAlexander Motin configtimer(1); 750a157e425SAlexander Motin } else 751a157e425SAlexander Motin profiling = 0; 7521af19ee4SAlexander Motin } else 7531af19ee4SAlexander Motin profiling--; 75443fe7d45SAlexander Motin ET_UNLOCK(); 75543fe7d45SAlexander Motin } 75643fe7d45SAlexander Motin 757a157e425SAlexander Motin /* 758a157e425SAlexander Motin * Switch to idle mode (all ticks handled). 759a157e425SAlexander Motin */ 760acccf7d8SDavide Italiano sbintime_t 761a157e425SAlexander Motin cpu_idleclock(void) 762a157e425SAlexander Motin { 7635b999a6bSDavide Italiano sbintime_t now, t; 764a157e425SAlexander Motin struct pcpu_state *state; 765a157e425SAlexander Motin 766a157e425SAlexander Motin if (idletick || busy || 7679dfc483cSAlexander Motin (periodic && (timer->et_flags & ET_FLAGS_PERCPU)) 7689dfc483cSAlexander Motin #ifdef DEVICE_POLLING 7699dfc483cSAlexander Motin || curcpu == CPU_FIRST() 7709dfc483cSAlexander Motin #endif 7719dfc483cSAlexander Motin ) 772acccf7d8SDavide Italiano return (-1); 773a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 774a157e425SAlexander Motin if (periodic) 775a157e425SAlexander Motin now = state->now; 776a157e425SAlexander Motin else 7775b999a6bSDavide Italiano now = sbinuptime(); 7785b999a6bSDavide Italiano CTR3(KTR_SPARE2, "idle at %d: now %d.%08x", 7795b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 7805b999a6bSDavide Italiano t = getnextcpuevent(1); 781a157e425SAlexander Motin ET_HW_LOCK(state); 782a157e425SAlexander Motin state->idle = 1; 783a157e425SAlexander Motin state->nextevent = t; 784a157e425SAlexander Motin if (!periodic) 7855b999a6bSDavide Italiano loadtimer(now, 0); 786a157e425SAlexander Motin ET_HW_UNLOCK(state); 7875b999a6bSDavide Italiano return (MAX(t - now, 0)); 788a157e425SAlexander Motin } 789a157e425SAlexander Motin 790a157e425SAlexander Motin /* 791a157e425SAlexander Motin * Switch to active mode (skip empty ticks). 792a157e425SAlexander Motin */ 793a157e425SAlexander Motin void 794a157e425SAlexander Motin cpu_activeclock(void) 795a157e425SAlexander Motin { 7965b999a6bSDavide Italiano sbintime_t now; 797a157e425SAlexander Motin struct pcpu_state *state; 798a157e425SAlexander Motin struct thread *td; 799a157e425SAlexander Motin 800a157e425SAlexander Motin state = DPCPU_PTR(timerstate); 801a157e425SAlexander Motin if (state->idle == 0 || busy) 802a157e425SAlexander Motin return; 803a157e425SAlexander Motin if (periodic) 804a157e425SAlexander Motin now = state->now; 805a157e425SAlexander Motin else 8065b999a6bSDavide Italiano now = sbinuptime(); 8075b999a6bSDavide Italiano CTR3(KTR_SPARE2, "active at %d: now %d.%08x", 8085b999a6bSDavide Italiano curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); 809a157e425SAlexander Motin spinlock_enter(); 810a157e425SAlexander Motin td = curthread; 811a157e425SAlexander Motin td->td_intr_nesting_level++; 8125b999a6bSDavide Italiano handleevents(now, 1); 813a157e425SAlexander Motin td->td_intr_nesting_level--; 814a157e425SAlexander Motin spinlock_exit(); 815a157e425SAlexander Motin } 816a157e425SAlexander Motin 817cfc4b56bSIan Lepore /* 818cfc4b56bSIan Lepore * Change the frequency of the given timer. This changes et->et_frequency and 819cfc4b56bSIan Lepore * if et is the active timer it reconfigures the timer on all CPUs. This is 820cfc4b56bSIan Lepore * intended to be a private interface for the use of et_change_frequency() only. 821cfc4b56bSIan Lepore */ 822cfc4b56bSIan Lepore void 823cfc4b56bSIan Lepore cpu_et_frequency(struct eventtimer *et, uint64_t newfreq) 824cfc4b56bSIan Lepore { 825cfc4b56bSIan Lepore 826cfc4b56bSIan Lepore ET_LOCK(); 827cfc4b56bSIan Lepore if (et == timer) { 828cfc4b56bSIan Lepore configtimer(0); 829cfc4b56bSIan Lepore et->et_frequency = newfreq; 830cfc4b56bSIan Lepore configtimer(1); 831cfc4b56bSIan Lepore } else 832cfc4b56bSIan Lepore et->et_frequency = newfreq; 833cfc4b56bSIan Lepore ET_UNLOCK(); 834cfc4b56bSIan Lepore } 835cfc4b56bSIan Lepore 8365b999a6bSDavide Italiano void 8375b999a6bSDavide Italiano cpu_new_callout(int cpu, sbintime_t bt, sbintime_t bt_opt) 838a157e425SAlexander Motin { 839a157e425SAlexander Motin struct pcpu_state *state; 840a157e425SAlexander Motin 8415b999a6bSDavide Italiano /* Do not touch anything if somebody reconfiguring timers. */ 8425b999a6bSDavide Italiano if (busy) 8435b999a6bSDavide Italiano return; 8445b999a6bSDavide Italiano CTR6(KTR_SPARE2, "new co at %d: on %d at %d.%08x - %d.%08x", 8455b999a6bSDavide Italiano curcpu, cpu, (int)(bt_opt >> 32), (u_int)(bt_opt & 0xffffffff), 8465b999a6bSDavide Italiano (int)(bt >> 32), (u_int)(bt & 0xffffffff)); 847efe67753SNathan Whitehorn 848efe67753SNathan Whitehorn KASSERT(!CPU_ABSENT(cpu), ("Absent CPU %d", cpu)); 849a157e425SAlexander Motin state = DPCPU_ID_PTR(cpu, timerstate); 850a157e425SAlexander Motin ET_HW_LOCK(state); 8515b999a6bSDavide Italiano 8525b999a6bSDavide Italiano /* 8535b999a6bSDavide Italiano * If there is callout time already set earlier -- do nothing. 8545b999a6bSDavide Italiano * This check may appear redundant because we check already in 8555b999a6bSDavide Italiano * callout_process() but this double check guarantees we're safe 8565b999a6bSDavide Italiano * with respect to race conditions between interrupts execution 8575b999a6bSDavide Italiano * and scheduling. 8585b999a6bSDavide Italiano */ 8595b999a6bSDavide Italiano state->nextcallopt = bt_opt; 8605b999a6bSDavide Italiano if (bt >= state->nextcall) 8615b999a6bSDavide Italiano goto done; 8625b999a6bSDavide Italiano state->nextcall = bt; 8635b999a6bSDavide Italiano /* If there is some other event set earlier -- do nothing. */ 8645b999a6bSDavide Italiano if (bt >= state->nextevent) 8655b999a6bSDavide Italiano goto done; 8665b999a6bSDavide Italiano state->nextevent = bt; 8675b999a6bSDavide Italiano /* If timer is periodic -- there is nothing to reprogram. */ 8685b999a6bSDavide Italiano if (periodic) 8695b999a6bSDavide Italiano goto done; 8705b999a6bSDavide Italiano /* If timer is global or of the current CPU -- reprogram it. */ 8715b999a6bSDavide Italiano if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || cpu == curcpu) { 8725b999a6bSDavide Italiano loadtimer(sbinuptime(), 0); 8735b999a6bSDavide Italiano done: 874a157e425SAlexander Motin ET_HW_UNLOCK(state); 875a157e425SAlexander Motin return; 876a157e425SAlexander Motin } 8775b999a6bSDavide Italiano /* Otherwise make other CPU to reprogram it. */ 878a157e425SAlexander Motin state->handle = 1; 8795b999a6bSDavide Italiano ET_HW_UNLOCK(state); 8805b999a6bSDavide Italiano #ifdef SMP 881a157e425SAlexander Motin ipi_cpu(cpu, IPI_HARDCLOCK); 882a157e425SAlexander Motin #endif 8835b999a6bSDavide Italiano } 884a157e425SAlexander Motin 885a157e425SAlexander Motin /* 886a157e425SAlexander Motin * Report or change the active event timers hardware. 887a157e425SAlexander Motin */ 88843fe7d45SAlexander Motin static int 889a157e425SAlexander Motin sysctl_kern_eventtimer_timer(SYSCTL_HANDLER_ARGS) 89043fe7d45SAlexander Motin { 89143fe7d45SAlexander Motin char buf[32]; 89243fe7d45SAlexander Motin struct eventtimer *et; 89343fe7d45SAlexander Motin int error; 89443fe7d45SAlexander Motin 89543fe7d45SAlexander Motin ET_LOCK(); 896a157e425SAlexander Motin et = timer; 89743fe7d45SAlexander Motin snprintf(buf, sizeof(buf), "%s", et->et_name); 89843fe7d45SAlexander Motin ET_UNLOCK(); 89943fe7d45SAlexander Motin error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 90043fe7d45SAlexander Motin ET_LOCK(); 901a157e425SAlexander Motin et = timer; 90243fe7d45SAlexander Motin if (error != 0 || req->newptr == NULL || 903a157e425SAlexander Motin strcasecmp(buf, et->et_name) == 0) { 90443fe7d45SAlexander Motin ET_UNLOCK(); 90543fe7d45SAlexander Motin return (error); 90643fe7d45SAlexander Motin } 907a157e425SAlexander Motin et = et_find(buf, 0, 0); 90843fe7d45SAlexander Motin if (et == NULL) { 90943fe7d45SAlexander Motin ET_UNLOCK(); 91043fe7d45SAlexander Motin return (ENOENT); 91143fe7d45SAlexander Motin } 91243fe7d45SAlexander Motin configtimer(0); 913a157e425SAlexander Motin et_free(timer); 914a157e425SAlexander Motin if (et->et_flags & ET_FLAGS_C3STOP) 91592597e06SJohn Baldwin cpu_disable_c3_sleep++; 916a157e425SAlexander Motin if (timer->et_flags & ET_FLAGS_C3STOP) 91792597e06SJohn Baldwin cpu_disable_c3_sleep--; 918afe41f2dSAlexander Motin periodic = want_periodic; 919a157e425SAlexander Motin timer = et; 920a157e425SAlexander Motin et_init(timer, timercb, NULL, NULL); 92143fe7d45SAlexander Motin configtimer(1); 92243fe7d45SAlexander Motin ET_UNLOCK(); 92343fe7d45SAlexander Motin return (error); 92443fe7d45SAlexander Motin } 925a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer, 92643fe7d45SAlexander Motin CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 927dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_timer, "A", "Chosen event timer"); 928a157e425SAlexander Motin 929a157e425SAlexander Motin /* 930a157e425SAlexander Motin * Report or change the active event timer periodicity. 931a157e425SAlexander Motin */ 932a157e425SAlexander Motin static int 933a157e425SAlexander Motin sysctl_kern_eventtimer_periodic(SYSCTL_HANDLER_ARGS) 934a157e425SAlexander Motin { 935a157e425SAlexander Motin int error, val; 936a157e425SAlexander Motin 937a157e425SAlexander Motin val = periodic; 938a157e425SAlexander Motin error = sysctl_handle_int(oidp, &val, 0, req); 939a157e425SAlexander Motin if (error != 0 || req->newptr == NULL) 940a157e425SAlexander Motin return (error); 941a157e425SAlexander Motin ET_LOCK(); 942a157e425SAlexander Motin configtimer(0); 943afe41f2dSAlexander Motin periodic = want_periodic = val; 944a157e425SAlexander Motin configtimer(1); 945a157e425SAlexander Motin ET_UNLOCK(); 946a157e425SAlexander Motin return (error); 947a157e425SAlexander Motin } 948a157e425SAlexander Motin SYSCTL_PROC(_kern_eventtimer, OID_AUTO, periodic, 949a157e425SAlexander Motin CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 950dd9595e7SAlexander Motin 0, 0, sysctl_kern_eventtimer_periodic, "I", "Enable event timer periodic mode"); 9516e3bf539SKonstantin Belousov 9526e3bf539SKonstantin Belousov #include "opt_ddb.h" 9536e3bf539SKonstantin Belousov 9546e3bf539SKonstantin Belousov #ifdef DDB 9556e3bf539SKonstantin Belousov #include <ddb/ddb.h> 9566e3bf539SKonstantin Belousov 9576e3bf539SKonstantin Belousov DB_SHOW_COMMAND(clocksource, db_show_clocksource) 9586e3bf539SKonstantin Belousov { 9596e3bf539SKonstantin Belousov struct pcpu_state *st; 9606e3bf539SKonstantin Belousov int c; 9616e3bf539SKonstantin Belousov 9626e3bf539SKonstantin Belousov CPU_FOREACH(c) { 9636e3bf539SKonstantin Belousov st = DPCPU_ID_PTR(c, timerstate); 9646e3bf539SKonstantin Belousov db_printf( 9656e3bf539SKonstantin Belousov "CPU %2d: action %d handle %d ipi %d idle %d\n" 9666e3bf539SKonstantin Belousov " now %#jx nevent %#jx (%jd)\n" 9676e3bf539SKonstantin Belousov " ntick %#jx (%jd) nhard %#jx (%jd)\n" 9686e3bf539SKonstantin Belousov " nstat %#jx (%jd) nprof %#jx (%jd)\n" 9696e3bf539SKonstantin Belousov " ncall %#jx (%jd) ncallopt %#jx (%jd)\n", 9706e3bf539SKonstantin Belousov c, st->action, st->handle, st->ipi, st->idle, 9716e3bf539SKonstantin Belousov (uintmax_t)st->now, 9726e3bf539SKonstantin Belousov (uintmax_t)st->nextevent, 9736e3bf539SKonstantin Belousov (uintmax_t)(st->nextevent - st->now) / tick_sbt, 9746e3bf539SKonstantin Belousov (uintmax_t)st->nexttick, 9756e3bf539SKonstantin Belousov (uintmax_t)(st->nexttick - st->now) / tick_sbt, 9766e3bf539SKonstantin Belousov (uintmax_t)st->nexthard, 9776e3bf539SKonstantin Belousov (uintmax_t)(st->nexthard - st->now) / tick_sbt, 9786e3bf539SKonstantin Belousov (uintmax_t)st->nextstat, 9796e3bf539SKonstantin Belousov (uintmax_t)(st->nextstat - st->now) / tick_sbt, 9806e3bf539SKonstantin Belousov (uintmax_t)st->nextprof, 9816e3bf539SKonstantin Belousov (uintmax_t)(st->nextprof - st->now) / tick_sbt, 9826e3bf539SKonstantin Belousov (uintmax_t)st->nextcall, 9836e3bf539SKonstantin Belousov (uintmax_t)(st->nextcall - st->now) / tick_sbt, 9846e3bf539SKonstantin Belousov (uintmax_t)st->nextcallopt, 9856e3bf539SKonstantin Belousov (uintmax_t)(st->nextcallopt - st->now) / tick_sbt); 9866e3bf539SKonstantin Belousov } 9876e3bf539SKonstantin Belousov } 9886e3bf539SKonstantin Belousov 9896e3bf539SKonstantin Belousov #endif 990