kern_clocksource.c revision 212992
1/*- 2 * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification, immediately at the beginning of the file. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/kern/kern_clocksource.c 212992 2010-09-22 05:32:37Z mav $"); 29 30/* 31 * Common routines to manage event timers hardware. 32 */ 33 34/* XEN has own timer routines now. */ 35#ifndef XEN 36 37#include "opt_device_polling.h" 38#include "opt_kdtrace.h" 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/bus.h> 43#include <sys/lock.h> 44#include <sys/kdb.h> 45#include <sys/ktr.h> 46#include <sys/mutex.h> 47#include <sys/proc.h> 48#include <sys/kernel.h> 49#include <sys/sched.h> 50#include <sys/smp.h> 51#include <sys/sysctl.h> 52#include <sys/timeet.h> 53#include <sys/timetc.h> 54 55#include <machine/atomic.h> 56#include <machine/clock.h> 57#include <machine/cpu.h> 58#include <machine/smp.h> 59 60#ifdef KDTRACE_HOOKS 61#include <sys/dtrace_bsd.h> 62cyclic_clock_func_t cyclic_clock_func[MAXCPU]; 63#endif 64 65int cpu_disable_deep_sleep = 0; /* Timer dies in C3. */ 66 67static void setuptimer(void); 68static void loadtimer(struct bintime *now, int first); 69static int doconfigtimer(void); 70static void configtimer(int start); 71static int round_freq(struct eventtimer *et, int freq); 72 73static void getnextcpuevent(struct bintime *event, int idle); 74static void getnextevent(struct bintime *event); 75static int handleevents(struct bintime *now, int fake); 76#ifdef SMP 77static void cpu_new_callout(int cpu, int ticks); 78#endif 79 80static struct mtx et_hw_mtx; 81 82#define ET_HW_LOCK(state) \ 83 { \ 84 if (timer->et_flags & ET_FLAGS_PERCPU) \ 85 mtx_lock_spin(&(state)->et_hw_mtx); \ 86 else \ 87 mtx_lock_spin(&et_hw_mtx); \ 88 } 89 90#define ET_HW_UNLOCK(state) \ 91 { \ 92 if (timer->et_flags & ET_FLAGS_PERCPU) \ 93 mtx_unlock_spin(&(state)->et_hw_mtx); \ 94 else \ 95 mtx_unlock_spin(&et_hw_mtx); \ 96 } 97 98static struct eventtimer *timer = NULL; 99static struct bintime timerperiod; /* Timer period for periodic mode. */ 100static struct bintime hardperiod; /* hardclock() events period. */ 101static struct bintime statperiod; /* statclock() events period. */ 102static struct bintime profperiod; /* profclock() events period. */ 103static struct bintime nexttick; /* Next global timer tick time. */ 104static u_int busy = 0; /* Reconfiguration is in progress. */ 105static int profiling = 0; /* Profiling events enabled. */ 106 107static char timername[32]; /* Wanted timer. */ 108TUNABLE_STR("kern.eventtimer.timer", timername, sizeof(timername)); 109 110static int singlemul = 0; /* Multiplier for periodic mode. */ 111TUNABLE_INT("kern.eventtimer.singlemul", &singlemul); 112SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul, 113 0, "Multiplier for periodic mode"); 114 115static u_int idletick = 0; /* Idle mode allowed. */ 116TUNABLE_INT("kern.eventtimer.idletick", &idletick); 117SYSCTL_INT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RW, &idletick, 118 0, "Run periodic events when idle"); 119 120static int periodic = 0; /* Periodic or one-shot mode. */ 121static int want_periodic = 0; /* What mode to prefer. */ 122TUNABLE_INT("kern.eventtimer.periodic", &want_periodic); 123 124struct pcpu_state { 125 struct mtx et_hw_mtx; /* Per-CPU timer mutex. */ 126 u_int action; /* Reconfiguration requests. */ 127 u_int handle; /* Immediate handle resuests. */ 128 struct bintime now; /* Last tick time. */ 129 struct bintime nextevent; /* Next scheduled event on this CPU. */ 130 struct bintime nexttick; /* Next timer tick time. */ 131 struct bintime nexthard; /* Next hardlock() event. */ 132 struct bintime nextstat; /* Next statclock() event. */ 133 struct bintime nextprof; /* Next profclock() event. */ 134 int ipi; /* This CPU needs IPI. */ 135 int idle; /* This CPU is in idle mode. */ 136}; 137 138static DPCPU_DEFINE(struct pcpu_state, timerstate); 139 140#define FREQ2BT(freq, bt) \ 141{ \ 142 (bt)->sec = 0; \ 143 (bt)->frac = ((uint64_t)0x8000000000000000 / (freq)) << 1; \ 144} 145#define BT2FREQ(bt) \ 146 (((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \ 147 ((bt)->frac >> 1)) 148 149/* 150 * Timer broadcast IPI handler. 151 */ 152int 153hardclockintr(void) 154{ 155 struct bintime now; 156 struct pcpu_state *state; 157 int done; 158 159 if (doconfigtimer() || busy) 160 return (FILTER_HANDLED); 161 state = DPCPU_PTR(timerstate); 162 now = state->now; 163 CTR4(KTR_SPARE2, "ipi at %d: now %d.%08x%08x", 164 curcpu, now.sec, (unsigned int)(now.frac >> 32), 165 (unsigned int)(now.frac & 0xffffffff)); 166 done = handleevents(&now, 0); 167 return (done ? FILTER_HANDLED : FILTER_STRAY); 168} 169 170/* 171 * Handle all events for specified time on this CPU 172 */ 173static int 174handleevents(struct bintime *now, int fake) 175{ 176 struct bintime t; 177 struct trapframe *frame; 178 struct pcpu_state *state; 179 uintfptr_t pc; 180 int usermode; 181 int done, runs; 182 183 CTR4(KTR_SPARE2, "handle at %d: now %d.%08x%08x", 184 curcpu, now->sec, (unsigned int)(now->frac >> 32), 185 (unsigned int)(now->frac & 0xffffffff)); 186 done = 0; 187 if (fake) { 188 frame = NULL; 189 usermode = 0; 190 pc = 0; 191 } else { 192 frame = curthread->td_intr_frame; 193 usermode = TRAPF_USERMODE(frame); 194 pc = TRAPF_PC(frame); 195 } 196#ifdef KDTRACE_HOOKS 197 /* 198 * If the DTrace hooks are configured and a callback function 199 * has been registered, then call it to process the high speed 200 * timers. 201 */ 202 if (!fake && cyclic_clock_func[curcpu] != NULL) 203 (*cyclic_clock_func[curcpu])(frame); 204#endif 205 runs = 0; 206 state = DPCPU_PTR(timerstate); 207 while (bintime_cmp(now, &state->nexthard, >=)) { 208 bintime_add(&state->nexthard, &hardperiod); 209 runs++; 210 } 211 if (runs) { 212 hardclock_anycpu(runs, usermode); 213 done = 1; 214 } 215 while (bintime_cmp(now, &state->nextstat, >=)) { 216 statclock(usermode); 217 bintime_add(&state->nextstat, &statperiod); 218 done = 1; 219 } 220 if (profiling) { 221 while (bintime_cmp(now, &state->nextprof, >=)) { 222 if (!fake) 223 profclock(usermode, pc); 224 bintime_add(&state->nextprof, &profperiod); 225 done = 1; 226 } 227 } else 228 state->nextprof = state->nextstat; 229 getnextcpuevent(&t, 0); 230 ET_HW_LOCK(state); 231 if (!busy) { 232 state->idle = 0; 233 state->nextevent = t; 234 loadtimer(now, 0); 235 } 236 ET_HW_UNLOCK(state); 237 return (done); 238} 239 240/* 241 * Schedule binuptime of the next event on current CPU. 242 */ 243static void 244getnextcpuevent(struct bintime *event, int idle) 245{ 246 struct bintime tmp; 247 struct pcpu_state *state; 248 int skip; 249 250 state = DPCPU_PTR(timerstate); 251 *event = state->nexthard; 252 if (idle) { /* If CPU is idle - ask callouts for how long. */ 253 skip = 4; 254 if (curcpu == CPU_FIRST() && tc_min_ticktock_freq > skip) 255 skip = tc_min_ticktock_freq; 256 skip = callout_tickstofirst(hz / skip) - 1; 257 CTR2(KTR_SPARE2, "skip at %d: %d", curcpu, skip); 258 tmp = hardperiod; 259 bintime_mul(&tmp, skip); 260 bintime_add(event, &tmp); 261 } else { /* If CPU is active - handle all types of events. */ 262 if (bintime_cmp(event, &state->nextstat, >)) 263 *event = state->nextstat; 264 if (profiling && 265 bintime_cmp(event, &state->nextprof, >)) 266 *event = state->nextprof; 267 } 268} 269 270/* 271 * Schedule binuptime of the next event on all CPUs. 272 */ 273static void 274getnextevent(struct bintime *event) 275{ 276 struct pcpu_state *state; 277#ifdef SMP 278 int cpu; 279#endif 280 int c; 281 282 state = DPCPU_PTR(timerstate); 283 *event = state->nextevent; 284 c = curcpu; 285#ifdef SMP 286 if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) { 287 CPU_FOREACH(cpu) { 288 if (curcpu == cpu) 289 continue; 290 state = DPCPU_ID_PTR(cpu, timerstate); 291 if (bintime_cmp(event, &state->nextevent, >)) { 292 *event = state->nextevent; 293 c = cpu; 294 } 295 } 296 } 297#endif 298 CTR5(KTR_SPARE2, "next at %d: next %d.%08x%08x by %d", 299 curcpu, event->sec, (unsigned int)(event->frac >> 32), 300 (unsigned int)(event->frac & 0xffffffff), c); 301} 302 303/* Hardware timer callback function. */ 304static void 305timercb(struct eventtimer *et, void *arg) 306{ 307 struct bintime now; 308 struct bintime *next; 309 struct pcpu_state *state; 310#ifdef SMP 311 int cpu, bcast; 312#endif 313 314 /* Do not touch anything if somebody reconfiguring timers. */ 315 if (busy) 316 return; 317 /* Update present and next tick times. */ 318 state = DPCPU_PTR(timerstate); 319 if (et->et_flags & ET_FLAGS_PERCPU) { 320 next = &state->nexttick; 321 } else 322 next = &nexttick; 323 if (periodic) { 324 now = *next; /* Ex-next tick time becomes present time. */ 325 bintime_add(next, &timerperiod); /* Next tick in 1 period. */ 326 } else { 327 binuptime(&now); /* Get present time from hardware. */ 328 next->sec = -1; /* Next tick is not scheduled yet. */ 329 } 330 state->now = now; 331 CTR4(KTR_SPARE2, "intr at %d: now %d.%08x%08x", 332 curcpu, now.sec, (unsigned int)(now.frac >> 32), 333 (unsigned int)(now.frac & 0xffffffff)); 334 335#ifdef SMP 336 /* Prepare broadcasting to other CPUs for non-per-CPU timers. */ 337 bcast = 0; 338 if ((et->et_flags & ET_FLAGS_PERCPU) == 0 && smp_started) { 339 CPU_FOREACH(cpu) { 340 state = DPCPU_ID_PTR(cpu, timerstate); 341 ET_HW_LOCK(state); 342 state->now = now; 343 if (bintime_cmp(&now, &state->nextevent, >=)) { 344 state->nextevent.sec++; 345 if (curcpu != cpu) { 346 state->ipi = 1; 347 bcast = 1; 348 } 349 } 350 ET_HW_UNLOCK(state); 351 } 352 } 353#endif 354 355 /* Handle events for this time on this CPU. */ 356 handleevents(&now, 0); 357 358#ifdef SMP 359 /* Broadcast interrupt to other CPUs for non-per-CPU timers. */ 360 if (bcast) { 361 CPU_FOREACH(cpu) { 362 if (curcpu == cpu) 363 continue; 364 state = DPCPU_ID_PTR(cpu, timerstate); 365 if (state->ipi) { 366 state->ipi = 0; 367 ipi_cpu(cpu, IPI_HARDCLOCK); 368 } 369 } 370 } 371#endif 372} 373 374/* 375 * Load new value into hardware timer. 376 */ 377static void 378loadtimer(struct bintime *now, int start) 379{ 380 struct pcpu_state *state; 381 struct bintime new; 382 struct bintime *next; 383 uint64_t tmp; 384 int eq; 385 386 if (periodic) { 387 if (start) { 388 /* 389 * Try to start all periodic timers aligned 390 * to period to make events synchronous. 391 */ 392 tmp = ((uint64_t)now->sec << 36) + (now->frac >> 28); 393 tmp = (tmp % (timerperiod.frac >> 28)) << 28; 394 tmp = timerperiod.frac - tmp; 395 new = timerperiod; 396 bintime_addx(&new, tmp); 397 CTR5(KTR_SPARE2, "load p at %d: now %d.%08x first in %d.%08x", 398 curcpu, now->sec, (unsigned int)(now->frac >> 32), 399 new.sec, (unsigned int)(new.frac >> 32)); 400 et_start(timer, &new, &timerperiod); 401 } 402 } else { 403 if (timer->et_flags & ET_FLAGS_PERCPU) { 404 state = DPCPU_PTR(timerstate); 405 next = &state->nexttick; 406 } else 407 next = &nexttick; 408 getnextevent(&new); 409 eq = bintime_cmp(&new, next, ==); 410 CTR5(KTR_SPARE2, "load at %d: next %d.%08x%08x eq %d", 411 curcpu, new.sec, (unsigned int)(new.frac >> 32), 412 (unsigned int)(new.frac & 0xffffffff), 413 eq); 414 if (!eq) { 415 *next = new; 416 bintime_sub(&new, now); 417 et_start(timer, &new, NULL); 418 } 419 } 420} 421 422/* 423 * Prepare event timer parameters after configuration changes. 424 */ 425static void 426setuptimer(void) 427{ 428 int freq; 429 430 if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 431 periodic = 0; 432 else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 433 periodic = 1; 434 singlemul = MIN(MAX(singlemul, 1), 20); 435 freq = hz * singlemul; 436 while (freq < (profiling ? profhz : stathz)) 437 freq += hz; 438 freq = round_freq(timer, freq); 439 FREQ2BT(freq, &timerperiod); 440} 441 442/* 443 * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler. 444 */ 445static int 446doconfigtimer(void) 447{ 448 struct bintime now; 449 struct pcpu_state *state; 450 451 state = DPCPU_PTR(timerstate); 452 switch (atomic_load_acq_int(&state->action)) { 453 case 1: 454 binuptime(&now); 455 ET_HW_LOCK(state); 456 loadtimer(&now, 1); 457 ET_HW_UNLOCK(state); 458 state->handle = 0; 459 atomic_store_rel_int(&state->action, 0); 460 return (1); 461 case 2: 462 ET_HW_LOCK(state); 463 et_stop(timer); 464 ET_HW_UNLOCK(state); 465 state->handle = 0; 466 atomic_store_rel_int(&state->action, 0); 467 return (1); 468 } 469 if (atomic_readandclear_int(&state->handle) && !busy) { 470 binuptime(&now); 471 handleevents(&now, 0); 472 return (1); 473 } 474 return (0); 475} 476 477/* 478 * Reconfigure specified timer. 479 * For per-CPU timers use IPI to make other CPUs to reconfigure. 480 */ 481static void 482configtimer(int start) 483{ 484 struct bintime now, next; 485 struct pcpu_state *state; 486 int cpu; 487 488 if (start) { 489 setuptimer(); 490 binuptime(&now); 491 } 492 critical_enter(); 493 ET_HW_LOCK(DPCPU_PTR(timerstate)); 494 if (start) { 495 /* Initialize time machine parameters. */ 496 next = now; 497 bintime_add(&next, &timerperiod); 498 if (periodic) 499 nexttick = next; 500 else 501 nexttick.sec = -1; 502 CPU_FOREACH(cpu) { 503 state = DPCPU_ID_PTR(cpu, timerstate); 504 state->now = now; 505 state->nextevent = next; 506 if (periodic) 507 state->nexttick = next; 508 else 509 state->nexttick.sec = -1; 510 state->nexthard = next; 511 state->nextstat = next; 512 state->nextprof = next; 513 hardclock_sync(cpu); 514 } 515 busy = 0; 516 /* Start global timer or per-CPU timer of this CPU. */ 517 loadtimer(&now, 1); 518 } else { 519 busy = 1; 520 /* Stop global timer or per-CPU timer of this CPU. */ 521 et_stop(timer); 522 } 523 ET_HW_UNLOCK(DPCPU_PTR(timerstate)); 524#ifdef SMP 525 /* If timer is global or there is no other CPUs yet - we are done. */ 526 if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) { 527 critical_exit(); 528 return; 529 } 530 /* Set reconfigure flags for other CPUs. */ 531 CPU_FOREACH(cpu) { 532 state = DPCPU_ID_PTR(cpu, timerstate); 533 atomic_store_rel_int(&state->action, 534 (cpu == curcpu) ? 0 : ( start ? 1 : 2)); 535 } 536 /* Broadcast reconfigure IPI. */ 537 ipi_all_but_self(IPI_HARDCLOCK); 538 /* Wait for reconfiguration completed. */ 539restart: 540 cpu_spinwait(); 541 CPU_FOREACH(cpu) { 542 if (cpu == curcpu) 543 continue; 544 state = DPCPU_ID_PTR(cpu, timerstate); 545 if (atomic_load_acq_int(&state->action)) 546 goto restart; 547 } 548#endif 549 critical_exit(); 550} 551 552/* 553 * Calculate nearest frequency supported by hardware timer. 554 */ 555static int 556round_freq(struct eventtimer *et, int freq) 557{ 558 uint64_t div; 559 560 if (et->et_frequency != 0) { 561 div = lmax((et->et_frequency + freq / 2) / freq, 1); 562 if (et->et_flags & ET_FLAGS_POW2DIV) 563 div = 1 << (flsl(div + div / 2) - 1); 564 freq = (et->et_frequency + div / 2) / div; 565 } 566 if (et->et_min_period.sec > 0) 567 freq = 0; 568 else if (et->et_min_period.frac != 0) 569 freq = min(freq, BT2FREQ(&et->et_min_period)); 570 if (et->et_max_period.sec == 0 && et->et_max_period.frac != 0) 571 freq = max(freq, BT2FREQ(&et->et_max_period)); 572 return (freq); 573} 574 575/* 576 * Configure and start event timers (BSP part). 577 */ 578void 579cpu_initclocks_bsp(void) 580{ 581 struct pcpu_state *state; 582 int base, div, cpu; 583 584 mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 585 CPU_FOREACH(cpu) { 586 state = DPCPU_ID_PTR(cpu, timerstate); 587 mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); 588 } 589#ifdef SMP 590 callout_new_inserted = cpu_new_callout; 591#endif 592 periodic = want_periodic; 593 /* Grab requested timer or the best of present. */ 594 if (timername[0]) 595 timer = et_find(timername, 0, 0); 596 if (timer == NULL && periodic) { 597 timer = et_find(NULL, 598 ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 599 } 600 if (timer == NULL) { 601 timer = et_find(NULL, 602 ET_FLAGS_ONESHOT, ET_FLAGS_ONESHOT); 603 } 604 if (timer == NULL && !periodic) { 605 timer = et_find(NULL, 606 ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); 607 } 608 if (timer == NULL) 609 panic("No usable event timer found!"); 610 et_init(timer, timercb, NULL, NULL); 611 612 /* Adapt to timer capabilities. */ 613 if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) 614 periodic = 0; 615 else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) 616 periodic = 1; 617 if (timer->et_flags & ET_FLAGS_C3STOP) 618 cpu_disable_deep_sleep++; 619 620 /* 621 * We honor the requested 'hz' value. 622 * We want to run stathz in the neighborhood of 128hz. 623 * We would like profhz to run as often as possible. 624 */ 625 if (singlemul <= 0 || singlemul > 20) { 626 if (hz >= 1500 || (hz % 128) == 0) 627 singlemul = 1; 628 else if (hz >= 750) 629 singlemul = 2; 630 else 631 singlemul = 4; 632 } 633 if (periodic) { 634 base = round_freq(timer, hz * singlemul); 635 singlemul = max((base + hz / 2) / hz, 1); 636 hz = (base + singlemul / 2) / singlemul; 637 if (base <= 128) 638 stathz = base; 639 else { 640 div = base / 128; 641 if (div >= singlemul && (div % singlemul) == 0) 642 div++; 643 stathz = base / div; 644 } 645 profhz = stathz; 646 while ((profhz + stathz) <= 128 * 64) 647 profhz += stathz; 648 profhz = round_freq(timer, profhz); 649 } else { 650 hz = round_freq(timer, hz); 651 stathz = round_freq(timer, 127); 652 profhz = round_freq(timer, stathz * 64); 653 } 654 tick = 1000000 / hz; 655 FREQ2BT(hz, &hardperiod); 656 FREQ2BT(stathz, &statperiod); 657 FREQ2BT(profhz, &profperiod); 658 ET_LOCK(); 659 configtimer(1); 660 ET_UNLOCK(); 661} 662 663/* 664 * Start per-CPU event timers on APs. 665 */ 666void 667cpu_initclocks_ap(void) 668{ 669 struct bintime now; 670 struct pcpu_state *state; 671 672 if (timer->et_flags & ET_FLAGS_PERCPU) { 673 state = DPCPU_PTR(timerstate); 674 binuptime(&now); 675 ET_HW_LOCK(state); 676 loadtimer(&now, 1); 677 ET_HW_UNLOCK(state); 678 } 679} 680 681/* 682 * Switch to profiling clock rates. 683 */ 684void 685cpu_startprofclock(void) 686{ 687 688 ET_LOCK(); 689 if (periodic) { 690 configtimer(0); 691 profiling = 1; 692 configtimer(1); 693 } else 694 profiling = 1; 695 ET_UNLOCK(); 696} 697 698/* 699 * Switch to regular clock rates. 700 */ 701void 702cpu_stopprofclock(void) 703{ 704 705 ET_LOCK(); 706 if (periodic) { 707 configtimer(0); 708 profiling = 0; 709 configtimer(1); 710 } else 711 profiling = 0; 712 ET_UNLOCK(); 713} 714 715/* 716 * Switch to idle mode (all ticks handled). 717 */ 718void 719cpu_idleclock(void) 720{ 721 struct bintime now, t; 722 struct pcpu_state *state; 723 724 if (idletick || busy || 725 (periodic && (timer->et_flags & ET_FLAGS_PERCPU)) 726#ifdef DEVICE_POLLING 727 || curcpu == CPU_FIRST() 728#endif 729 ) 730 return; 731 state = DPCPU_PTR(timerstate); 732 if (periodic) 733 now = state->now; 734 else 735 binuptime(&now); 736 CTR4(KTR_SPARE2, "idle at %d: now %d.%08x%08x", 737 curcpu, now.sec, (unsigned int)(now.frac >> 32), 738 (unsigned int)(now.frac & 0xffffffff)); 739 getnextcpuevent(&t, 1); 740 ET_HW_LOCK(state); 741 state->idle = 1; 742 state->nextevent = t; 743 if (!periodic) 744 loadtimer(&now, 0); 745 ET_HW_UNLOCK(state); 746} 747 748/* 749 * Switch to active mode (skip empty ticks). 750 */ 751void 752cpu_activeclock(void) 753{ 754 struct bintime now; 755 struct pcpu_state *state; 756 struct thread *td; 757 758 state = DPCPU_PTR(timerstate); 759 if (state->idle == 0 || busy) 760 return; 761 if (periodic) 762 now = state->now; 763 else 764 binuptime(&now); 765 CTR4(KTR_SPARE2, "active at %d: now %d.%08x%08x", 766 curcpu, now.sec, (unsigned int)(now.frac >> 32), 767 (unsigned int)(now.frac & 0xffffffff)); 768 spinlock_enter(); 769 td = curthread; 770 td->td_intr_nesting_level++; 771 handleevents(&now, 1); 772 td->td_intr_nesting_level--; 773 spinlock_exit(); 774} 775 776#ifdef SMP 777static void 778cpu_new_callout(int cpu, int ticks) 779{ 780 struct bintime tmp; 781 struct pcpu_state *state; 782 783 CTR3(KTR_SPARE2, "new co at %d: on %d in %d", 784 curcpu, cpu, ticks); 785 state = DPCPU_ID_PTR(cpu, timerstate); 786 ET_HW_LOCK(state); 787 if (state->idle == 0 || busy) { 788 ET_HW_UNLOCK(state); 789 return; 790 } 791 /* 792 * If timer is periodic - just update next event time for target CPU. 793 * If timer is global - there is chance it is already programmed. 794 */ 795 if (periodic || (timer->et_flags & ET_FLAGS_PERCPU) == 0) { 796 state->nextevent = state->nexthard; 797 tmp = hardperiod; 798 bintime_mul(&tmp, ticks - 1); 799 bintime_add(&state->nextevent, &tmp); 800 if (periodic || 801 bintime_cmp(&state->nextevent, &nexttick, >=)) { 802 ET_HW_UNLOCK(state); 803 return; 804 } 805 } 806 /* 807 * Otherwise we have to wake that CPU up, as we can't get present 808 * bintime to reprogram global timer from here. If timer is per-CPU, 809 * we by definition can't do it from here. 810 */ 811 ET_HW_UNLOCK(state); 812 if (timer->et_flags & ET_FLAGS_PERCPU) { 813 state->handle = 1; 814 ipi_cpu(cpu, IPI_HARDCLOCK); 815 } else { 816 if (!cpu_idle_wakeup(cpu)) 817 ipi_cpu(cpu, IPI_AST); 818 } 819} 820#endif 821 822/* 823 * Report or change the active event timers hardware. 824 */ 825static int 826sysctl_kern_eventtimer_timer(SYSCTL_HANDLER_ARGS) 827{ 828 char buf[32]; 829 struct eventtimer *et; 830 int error; 831 832 ET_LOCK(); 833 et = timer; 834 snprintf(buf, sizeof(buf), "%s", et->et_name); 835 ET_UNLOCK(); 836 error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 837 ET_LOCK(); 838 et = timer; 839 if (error != 0 || req->newptr == NULL || 840 strcasecmp(buf, et->et_name) == 0) { 841 ET_UNLOCK(); 842 return (error); 843 } 844 et = et_find(buf, 0, 0); 845 if (et == NULL) { 846 ET_UNLOCK(); 847 return (ENOENT); 848 } 849 configtimer(0); 850 et_free(timer); 851 if (et->et_flags & ET_FLAGS_C3STOP) 852 cpu_disable_deep_sleep++; 853 if (timer->et_flags & ET_FLAGS_C3STOP) 854 cpu_disable_deep_sleep--; 855 periodic = want_periodic; 856 timer = et; 857 et_init(timer, timercb, NULL, NULL); 858 configtimer(1); 859 ET_UNLOCK(); 860 return (error); 861} 862SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer, 863 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 864 0, 0, sysctl_kern_eventtimer_timer, "A", "Chosen event timer"); 865 866/* 867 * Report or change the active event timer periodicity. 868 */ 869static int 870sysctl_kern_eventtimer_periodic(SYSCTL_HANDLER_ARGS) 871{ 872 int error, val; 873 874 val = periodic; 875 error = sysctl_handle_int(oidp, &val, 0, req); 876 if (error != 0 || req->newptr == NULL) 877 return (error); 878 ET_LOCK(); 879 configtimer(0); 880 periodic = want_periodic = val; 881 configtimer(1); 882 ET_UNLOCK(); 883 return (error); 884} 885SYSCTL_PROC(_kern_eventtimer, OID_AUTO, periodic, 886 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 887 0, 0, sysctl_kern_eventtimer_periodic, "I", "Enable event timer periodic mode"); 888 889#endif 890