summaryrefslogtreecommitdiffstats
path: root/sys/x86
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2010-07-14 13:31:27 +0000
committermav <mav@FreeBSD.org>2010-07-14 13:31:27 +0000
commitb8b00841c93af095bbb283ea2d9a8662a7c55687 (patch)
tree1e8ec2fbb18fd313878fd2b976983c1a5124d4e3 /sys/x86
parent189daad0ad43b75dc71517a777d02c5e3e86a3f8 (diff)
downloadFreeBSD-src-b8b00841c93af095bbb283ea2d9a8662a7c55687.zip
FreeBSD-src-b8b00841c93af095bbb283ea2d9a8662a7c55687.tar.gz
Move timeevents.c to MI code, as it is not x86-specific. I already have
it working on Marvell ARM SoCs, and it would be nice to unify timer code between more platforms.
Diffstat (limited to 'sys/x86')
-rw-r--r--sys/x86/x86/timeevents.c508
1 files changed, 0 insertions, 508 deletions
diff --git a/sys/x86/x86/timeevents.c b/sys/x86/x86/timeevents.c
deleted file mode 100644
index 697275a..0000000
--- a/sys/x86/x86/timeevents.c
+++ /dev/null
@@ -1,508 +0,0 @@
-/*-
- * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer,
- * without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Common routines to manage event timers hardware.
- */
-
-/* XEN has own timer routines now. */
-#ifndef XEN
-
-#include "opt_kdtrace.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/lock.h>
-#include <sys/kdb.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/kernel.h>
-#include <sys/sched.h>
-#include <sys/smp.h>
-#include <sys/sysctl.h>
-#include <sys/timeet.h>
-
-#include <machine/atomic.h>
-#include <machine/clock.h>
-#include <machine/cpu.h>
-#include <machine/smp.h>
-
-#ifdef KDTRACE_HOOKS
-#include <sys/dtrace_bsd.h>
-cyclic_clock_func_t cyclic_clock_func[MAXCPU];
-#endif
-
-static void cpu_restartclocks(void);
-static void timercheck(void);
-inline static int doconfigtimer(int i);
-static void configtimer(int i);
-
-static struct eventtimer *timer[2] = { NULL, NULL };
-static int timertest = 0;
-static int timerticks[2] = { 0, 0 };
-static int profiling_on = 0;
-static struct bintime timerperiod[2];
-
-static char timername[2][32];
-TUNABLE_STR("kern.eventtimer.timer1", timername[0], sizeof(*timername));
-TUNABLE_STR("kern.eventtimer.timer2", timername[1], sizeof(*timername));
-
-static u_int singlemul = 0;
-TUNABLE_INT("kern.eventtimer.singlemul", &singlemul);
-SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul,
- 0, "Multiplier, used in single timer mode");
-
-typedef u_int tc[2];
-static DPCPU_DEFINE(tc, configtimer);
-
-#define FREQ2BT(freq, bt) \
-{ \
- (bt)->sec = 0; \
- (bt)->frac = ((uint64_t)0x8000000000000000 / (freq)) << 1; \
-}
-#define BT2FREQ(bt, freq) \
-{ \
- *(freq) = ((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \
- ((bt)->frac >> 1); \
-}
-
-/* Per-CPU timer1 handler. */
-static int
-hardclockhandler(struct trapframe *frame)
-{
-
-#ifdef KDTRACE_HOOKS
- /*
- * If the DTrace hooks are configured and a callback function
- * has been registered, then call it to process the high speed
- * timers.
- */
- int cpu = curcpu;
- if (cyclic_clock_func[cpu] != NULL)
- (*cyclic_clock_func[cpu])(frame);
-#endif
-
- timer1clock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
- return (FILTER_HANDLED);
-}
-
-/* Per-CPU timer2 handler. */
-static int
-statclockhandler(struct trapframe *frame)
-{
-
- timer2clock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
- return (FILTER_HANDLED);
-}
-
-/* timer1 broadcast IPI handler. */
-int
-hardclockintr(struct trapframe *frame)
-{
-
- if (doconfigtimer(0))
- return (FILTER_HANDLED);
- return (hardclockhandler(frame));
-}
-
-/* timer2 broadcast IPI handler. */
-int
-statclockintr(struct trapframe *frame)
-{
-
- if (doconfigtimer(1))
- return (FILTER_HANDLED);
- return (statclockhandler(frame));
-}
-
-/* timer1 callback. */
-static void
-timer1cb(struct eventtimer *et, void *arg)
-{
-
-#ifdef SMP
- /* Broadcast interrupt to other CPUs for non-per-CPU timers */
- if (smp_started && (et->et_flags & ET_FLAGS_PERCPU) == 0)
- ipi_all_but_self(IPI_HARDCLOCK);
-#endif
- if (timertest) {
- if ((et->et_flags & ET_FLAGS_PERCPU) == 0 || curcpu == 0) {
- timerticks[0]++;
- if (timerticks[0] >= timer1hz) {
- ET_LOCK();
- timercheck();
- ET_UNLOCK();
- }
- }
- }
- hardclockhandler(curthread->td_intr_frame);
-}
-
-/* timer2 callback. */
-static void
-timer2cb(struct eventtimer *et, void *arg)
-{
-
-#ifdef SMP
- /* Broadcast interrupt to other CPUs for non-per-CPU timers */
- if (smp_started && (et->et_flags & ET_FLAGS_PERCPU) == 0)
- ipi_all_but_self(IPI_STATCLOCK);
-#endif
- if (timertest) {
- if ((et->et_flags & ET_FLAGS_PERCPU) == 0 || curcpu == 0) {
- timerticks[1]++;
- if (timerticks[1] >= timer2hz * 2) {
- ET_LOCK();
- timercheck();
- ET_UNLOCK();
- }
- }
- }
- statclockhandler(curthread->td_intr_frame);
-}
-
-/*
- * Check that both timers are running with at least 1/4 of configured rate.
- * If not - replace the broken one.
- */
-static void
-timercheck(void)
-{
-
- if (!timertest)
- return;
- timertest = 0;
- if (timerticks[0] * 4 < timer1hz) {
- printf("Event timer \"%s\" is dead.\n", timer[0]->et_name);
- timer1hz = 0;
- configtimer(0);
- et_ban(timer[0]);
- et_free(timer[0]);
- timer[0] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
- if (timer[0] == NULL) {
- timer2hz = 0;
- configtimer(1);
- et_free(timer[1]);
- timer[1] = NULL;
- timer[0] = timer[1];
- }
- et_init(timer[0], timer1cb, NULL, NULL);
- cpu_restartclocks();
- return;
- }
- if (timerticks[1] * 4 < timer2hz) {
- printf("Event timer \"%s\" is dead.\n", timer[1]->et_name);
- timer2hz = 0;
- configtimer(1);
- et_ban(timer[1]);
- et_free(timer[1]);
- timer[1] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
- if (timer[1] != NULL)
- et_init(timer[1], timer2cb, NULL, NULL);
- cpu_restartclocks();
- return;
- }
-}
-
-/*
- * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler.
- */
-inline static int
-doconfigtimer(int i)
-{
- tc *conf;
-
- conf = DPCPU_PTR(configtimer);
- if (atomic_load_acq_int(*conf + i)) {
- if (i == 0 ? timer1hz : timer2hz)
- et_start(timer[i], NULL, &timerperiod[i]);
- else
- et_stop(timer[i]);
- atomic_store_rel_int(*conf + i, 0);
- return (1);
- }
- return (0);
-}
-
-/*
- * Reconfigure specified timer.
- * For per-CPU timers use IPI to make other CPUs to reconfigure.
- */
-static void
-configtimer(int i)
-{
-#ifdef SMP
- tc *conf;
- int cpu;
-
- critical_enter();
-#endif
- /* Start/stop global timer or per-CPU timer of this CPU. */
- if (i == 0 ? timer1hz : timer2hz)
- et_start(timer[i], NULL, &timerperiod[i]);
- else
- et_stop(timer[i]);
-#ifdef SMP
- if ((timer[i]->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) {
- critical_exit();
- return;
- }
- /* Set reconfigure flags for other CPUs. */
- CPU_FOREACH(cpu) {
- conf = DPCPU_ID_PTR(cpu, configtimer);
- atomic_store_rel_int(*conf + i, (cpu == curcpu) ? 0 : 1);
- }
- /* Send reconfigure IPI. */
- ipi_all_but_self(i == 0 ? IPI_HARDCLOCK : IPI_STATCLOCK);
- /* Wait for reconfiguration completed. */
-restart:
- cpu_spinwait();
- CPU_FOREACH(cpu) {
- if (cpu == curcpu)
- continue;
- conf = DPCPU_ID_PTR(cpu, configtimer);
- if (atomic_load_acq_int(*conf + i))
- goto restart;
- }
- critical_exit();
-#endif
-}
-
-/*
- * Configure and start event timers.
- */
-void
-cpu_initclocks_bsp(void)
-{
- int base, div;
-
- timer[0] = et_find(timername[0], ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
- if (timer[0] == NULL)
- timer[0] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
- if (timer[0] == NULL)
- panic("No usable event timer found!");
- et_init(timer[0], timer1cb, NULL, NULL);
- timer[1] = et_find(timername[1][0] ? timername[1] : NULL,
- ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
- if (timer[1])
- et_init(timer[1], timer2cb, NULL, NULL);
- /*
- * We honor the requested 'hz' value.
- * We want to run stathz in the neighborhood of 128hz.
- * We would like profhz to run as often as possible.
- */
- if (singlemul == 0) {
- if (hz >= 1500 || (hz % 128) == 0)
- singlemul = 1;
- else if (hz >= 750)
- singlemul = 2;
- else
- singlemul = 4;
- }
- if (timer[1] == NULL) {
- base = hz * singlemul;
- if (base < 128)
- stathz = base;
- else {
- div = base / 128;
- if (div % 2 == 0)
- div++;
- stathz = base / div;
- }
- profhz = stathz;
- while ((profhz + stathz) <= 8192)
- profhz += stathz;
- } else {
- stathz = 128;
- profhz = stathz * 64;
- }
- ET_LOCK();
- cpu_restartclocks();
- ET_UNLOCK();
-}
-
-/* Start per-CPU event timers on APs. */
-void
-cpu_initclocks_ap(void)
-{
-
- ET_LOCK();
- if (timer[0]->et_flags & ET_FLAGS_PERCPU)
- et_start(timer[0], NULL, &timerperiod[0]);
- if (timer[1] && timer[1]->et_flags & ET_FLAGS_PERCPU)
- et_start(timer[1], NULL, &timerperiod[1]);
- ET_UNLOCK();
-}
-
-/* Reconfigure and restart event timers after configuration changes. */
-static void
-cpu_restartclocks(void)
-{
-
- /* Stop all event timers. */
- timertest = 0;
- if (timer1hz) {
- timer1hz = 0;
- configtimer(0);
- }
- if (timer[1] && timer2hz) {
- timer2hz = 0;
- configtimer(1);
- }
- /* Calculate new event timers parameters. */
- if (timer[1] == NULL) {
- timer1hz = hz * singlemul;
- while (timer1hz < (profiling_on ? profhz : stathz))
- timer1hz += hz;
- timer2hz = 0;
- } else {
- timer1hz = hz;
- timer2hz = profiling_on ? profhz : stathz;
- }
- printf("Starting kernel event timers: %s @ %dHz, %s @ %dHz\n",
- timer[0]->et_name, timer1hz,
- timer[1] ? timer[1]->et_name : "NONE", timer2hz);
- /* Restart event timers. */
- FREQ2BT(timer1hz, &timerperiod[0]);
- configtimer(0);
- if (timer[1]) {
- timerticks[0] = 0;
- timerticks[1] = 0;
- FREQ2BT(timer2hz, &timerperiod[1]);
- configtimer(1);
- timertest = 1;
- }
-}
-
-/* Switch to profiling clock rates. */
-void
-cpu_startprofclock(void)
-{
-
- ET_LOCK();
- profiling_on = 1;
- cpu_restartclocks();
- ET_UNLOCK();
-}
-
-/* Switch to regular clock rates. */
-void
-cpu_stopprofclock(void)
-{
-
- ET_LOCK();
- profiling_on = 0;
- cpu_restartclocks();
- ET_UNLOCK();
-}
-
-/* Report or change the active event timers hardware. */
-static int
-sysctl_kern_eventtimer_timer1(SYSCTL_HANDLER_ARGS)
-{
- char buf[32];
- struct eventtimer *et;
- int error;
-
- ET_LOCK();
- et = timer[0];
- snprintf(buf, sizeof(buf), "%s", et->et_name);
- ET_UNLOCK();
- error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
- ET_LOCK();
- et = timer[0];
- if (error != 0 || req->newptr == NULL ||
- strcmp(buf, et->et_name) == 0) {
- ET_UNLOCK();
- return (error);
- }
- et = et_find(buf, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
- if (et == NULL) {
- ET_UNLOCK();
- return (ENOENT);
- }
- timer1hz = 0;
- configtimer(0);
- et_free(timer[0]);
- timer[0] = et;
- et_init(timer[0], timer1cb, NULL, NULL);
- cpu_restartclocks();
- ET_UNLOCK();
- return (error);
-}
-SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer1,
- CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
- 0, 0, sysctl_kern_eventtimer_timer1, "A", "Primary event timer");
-
-static int
-sysctl_kern_eventtimer_timer2(SYSCTL_HANDLER_ARGS)
-{
- char buf[32];
- struct eventtimer *et;
- int error;
-
- ET_LOCK();
- et = timer[1];
- if (et == NULL)
- snprintf(buf, sizeof(buf), "NONE");
- else
- snprintf(buf, sizeof(buf), "%s", et->et_name);
- ET_UNLOCK();
- error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
- ET_LOCK();
- et = timer[1];
- if (error != 0 || req->newptr == NULL ||
- strcmp(buf, et ? et->et_name : "NONE") == 0) {
- ET_UNLOCK();
- return (error);
- }
- et = et_find(buf, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
- if (et == NULL && strcasecmp(buf, "NONE") != 0) {
- ET_UNLOCK();
- return (ENOENT);
- }
- if (timer[1] != NULL) {
- timer2hz = 0;
- configtimer(1);
- et_free(timer[1]);
- }
- timer[1] = et;
- if (timer[1] != NULL)
- et_init(timer[1], timer2cb, NULL, NULL);
- cpu_restartclocks();
- ET_UNLOCK();
- return (error);
-}
-SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer2,
- CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
- 0, 0, sysctl_kern_eventtimer_timer2, "A", "Secondary event timer");
-
-#endif
-
OpenPOWER on IntegriCloud