summaryrefslogtreecommitdiffstats
path: root/sys/mips/mips/tick.c
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2010-07-23 07:46:55 +0000
committermav <mav@FreeBSD.org>2010-07-23 07:46:55 +0000
commita39ae55cf406863806960ddf64d069ff79dda61f (patch)
treec4e66c41d889e7561032f3d550f7fd87a2ff9845 /sys/mips/mips/tick.c
parent6c308fec858ce130eceb0bbe485ab8b6252bc548 (diff)
downloadFreeBSD-src-a39ae55cf406863806960ddf64d069ff79dda61f.zip
FreeBSD-src-a39ae55cf406863806960ddf64d069ff79dda61f.tar.gz
Update MIPS timer code (except RMI) to utilize new MI event timer
infrastructure. Reviewed by: neel
Diffstat (limited to 'sys/mips/mips/tick.c')
-rw-r--r--sys/mips/mips/tick.c228
1 files changed, 116 insertions, 112 deletions
diff --git a/sys/mips/mips/tick.c b/sys/mips/mips/tick.c
index 5432c42..06c9aa7 100644
--- a/sys/mips/mips/tick.c
+++ b/sys/mips/mips/tick.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/power.h>
#include <sys/smp.h>
#include <sys/time.h>
+#include <sys/timeet.h>
#include <sys/timetc.h>
#include <machine/hwfunc.h>
@@ -56,8 +57,8 @@ uint64_t counter_freq;
struct timecounter *platform_timecounter;
-static uint64_t cycles_per_tick;
-static uint64_t cycles_per_usec;
+static DPCPU_DEFINE(uint32_t, cycles_per_tick);
+static uint32_t cycles_per_usec;
static u_int32_t counter_upper = 0;
static u_int32_t counter_lower_last = 0;
@@ -65,6 +66,15 @@ static u_int32_t counter_lower_last = 0;
static DPCPU_DEFINE(uint32_t, compare_ticks);
static DPCPU_DEFINE(uint32_t, lost_ticks);
+struct clock_softc {
+ int intr_rid;
+ struct resource *intr_res;
+ void *intr_handler;
+ struct timecounter tc;
+ struct eventtimer et;
+};
+static struct clock_softc *softc;
+
/*
* Device methods
*/
@@ -73,15 +83,6 @@ static void clock_identify(driver_t *, device_t);
static int clock_attach(device_t);
static unsigned counter_get_timecount(struct timecounter *tc);
-static struct timecounter counter_timecounter = {
- counter_get_timecount, /* get_timecount */
- 0, /* no poll_pps */
- 0xffffffffu, /* counter_mask */
- 0, /* frequency */
- "MIPS32", /* name */
- 800, /* quality (adjusted in code) */
-};
-
void
mips_timer_early_init(uint64_t clock_hz)
{
@@ -94,8 +95,6 @@ void
platform_initclocks(void)
{
- tc_init(&counter_timecounter);
-
if (platform_timecounter != NULL)
tc_init(platform_timecounter);
}
@@ -140,40 +139,7 @@ mips_timer_init_params(uint64_t platform_counter_freq, int double_count)
if (double_count != 0)
counter_freq /= 2;
- /*
- * We want to run stathz in the neighborhood of 128hz. We would
- * like profhz to run as often as possible, so we let it run on
- * each clock tick. We try to honor the requested 'hz' value as
- * much as possible.
- *
- * If 'hz' is above 1500, then we just let the timer
- * (and profhz) run at hz. If 'hz' is below 1500 but above
- * 750, then we let the timer run at 2 * 'hz'. If 'hz'
- * is below 750 then we let the timer run at 4 * 'hz'.
- */
- if (hz >= 1500)
- timer1hz = hz;
- else if (hz >= 750)
- timer1hz = hz * 2;
- else
- timer1hz = hz * 4;
-
- if (timer1hz < 128)
- stathz = timer1hz;
- else
- stathz = timer1hz / (timer1hz / 128);
- profhz = timer1hz;
-
- cycles_per_tick = counter_freq / timer1hz;
cycles_per_usec = counter_freq / (1 * 1000 * 1000);
-
- counter_timecounter.tc_frequency = counter_freq;
- printf("hz=%d timer1hz:%d cyl_per_tick:%jd cyl_per_usec:%jd freq:%jd\n",
- hz,
- timer1hz,
- cycles_per_tick,
- cycles_per_usec,
- counter_freq);
set_cputicker(tick_ticker, counter_freq, 1);
}
@@ -183,13 +149,14 @@ sysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS)
int error;
uint64_t freq;
- if (counter_timecounter.tc_frequency == 0)
+ if (softc == NULL)
return (EOPNOTSUPP);
freq = counter_freq;
error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
if (error == 0 && req->newptr != NULL) {
counter_freq = freq;
- counter_timecounter.tc_frequency = counter_freq;
+ softc->et.et_frequency = counter_freq;
+ softc->tc.tc_frequency = counter_freq;
}
return (error);
}
@@ -205,19 +172,6 @@ counter_get_timecount(struct timecounter *tc)
return (mips_rd_count());
}
-
-void
-cpu_startprofclock(void)
-{
- /* nothing to do */
-}
-
-void
-cpu_stopprofclock(void)
-{
- /* nothing to do */
-}
-
/*
* Wait for about n microseconds (at least!).
*/
@@ -251,23 +205,62 @@ DELAY(int n)
}
}
+static int
+clock_start(struct eventtimer *et,
+ struct bintime *first, struct bintime *period)
+{
+ uint32_t fdiv, div, next;
+
+ if (period != NULL) {
+ div = (et->et_frequency * (period->frac >> 32)) >> 32;
+ if (period->sec != 0)
+ div += et->et_frequency * period->sec;
+ } else
+ div = 0;
+ if (first != NULL) {
+ fdiv = (et->et_frequency * (first->frac >> 32)) >> 32;
+ if (first->sec != 0)
+ fdiv += et->et_frequency * first->sec;
+ } else
+ fdiv = div;
+ DPCPU_SET(cycles_per_tick, div);
+ next = mips_rd_count() + fdiv;
+ DPCPU_SET(compare_ticks, next);
+ mips_wr_compare(next);
+ return (0);
+}
+
+static int
+clock_stop(struct eventtimer *et)
+{
+
+ DPCPU_SET(cycles_per_tick, 0);
+ mips_wr_compare(0xffffffff);
+ return (0);
+}
+
/*
* Device section of file below
*/
static int
clock_intr(void *arg)
{
- struct trapframe *tf;
+ struct clock_softc *sc = (struct clock_softc *)arg;
+ uint32_t cycles_per_tick;
uint32_t count, compare_last, compare_next, lost_ticks;
+ cycles_per_tick = DPCPU_GET(cycles_per_tick);
/*
* Set next clock edge.
*/
count = mips_rd_count();
compare_last = DPCPU_GET(compare_ticks);
- compare_next = count + cycles_per_tick;
- DPCPU_SET(compare_ticks, compare_next);
- mips_wr_compare(compare_next);
+ if (cycles_per_tick > 0) {
+ compare_next = count + cycles_per_tick;
+ DPCPU_SET(compare_ticks, compare_next);
+ mips_wr_compare(compare_next);
+ } else
+ mips_wr_compare(0xffffffff);
critical_enter();
if (count < counter_lower_last) {
@@ -275,45 +268,34 @@ clock_intr(void *arg)
counter_lower_last = count;
}
- /*
- * Magic. Setting up with an arg of NULL means we get passed tf.
- */
- tf = (struct trapframe *)arg;
+ if (cycles_per_tick > 0) {
- /*
- * Account for the "lost time" between when the timer interrupt fired
- * and when 'clock_intr' actually started executing.
- */
- lost_ticks = DPCPU_GET(lost_ticks);
- lost_ticks += count - compare_last;
-
- /*
- * If the COUNT and COMPARE registers are no longer in sync then make
- * up some reasonable value for the 'lost_ticks'.
- *
- * This could happen, for e.g., after we resume normal operations after
- * exiting the debugger.
- */
- if (lost_ticks > 2 * cycles_per_tick)
- lost_ticks = cycles_per_tick;
-
- while (lost_ticks >= cycles_per_tick) {
- timer1clock(TRAPF_USERMODE(tf), tf->pc);
- lost_ticks -= cycles_per_tick;
+ /*
+ * Account for the "lost time" between when the timer interrupt
+ * fired and when 'clock_intr' actually started executing.
+ */
+ lost_ticks = DPCPU_GET(lost_ticks);
+ lost_ticks += count - compare_last;
+
+ /*
+ * If the COUNT and COMPARE registers are no longer in sync
+ * then make up some reasonable value for the 'lost_ticks'.
+ *
+ * This could happen, for e.g., after we resume normal
+ * operations after exiting the debugger.
+ */
+ if (lost_ticks > 2 * cycles_per_tick)
+ lost_ticks = cycles_per_tick;
+
+ while (lost_ticks >= cycles_per_tick) {
+ if (sc->et.et_active)
+ sc->et.et_event_cb(&sc->et, sc->et.et_arg);
+ lost_ticks -= cycles_per_tick;
+ }
+ DPCPU_SET(lost_ticks, lost_ticks);
}
- DPCPU_SET(lost_ticks, lost_ticks);
-
-#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 = PCPU_GET(cpuid);
- if (cyclic_clock_func[cpu] != NULL)
- (*cyclic_clock_func[cpu])(tf);
-#endif
- timer1clock(TRAPF_USERMODE(tf), tf->pc);
+ if (sc->et.et_active)
+ sc->et.et_event_cb(&sc->et, sc->et.et_arg);
critical_exit();
return (FILTER_HANDLED);
}
@@ -339,25 +321,45 @@ clock_identify(driver_t * drv, device_t parent)
static int
clock_attach(device_t dev)
{
- struct resource *irq;
+ struct clock_softc *sc;
int error;
- int rid;
- rid = 0;
- irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 5, 5, 1, RF_ACTIVE);
- if (irq == NULL) {
+ softc = sc = device_get_softc(dev);
+ sc->intr_rid = 0;
+ sc->intr_res = bus_alloc_resource(dev,
+ SYS_RES_IRQ, &sc->intr_rid, 5, 5, 1, RF_ACTIVE);
+ if (sc->intr_res == NULL) {
device_printf(dev, "failed to allocate irq\n");
return (ENXIO);
}
- error = bus_setup_intr(dev, irq, INTR_TYPE_CLK, clock_intr, NULL,
- NULL, NULL);
-
+ error = bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK,
+ clock_intr, NULL, sc, &sc->intr_handler);
if (error != 0) {
device_printf(dev, "bus_setup_intr returned %d\n", error);
return (error);
}
- mips_wr_compare(mips_rd_count() + counter_freq / hz);
+ sc->tc.tc_get_timecount = counter_get_timecount;
+ sc->tc.tc_counter_mask = 0xffffffff;
+ sc->tc.tc_frequency = counter_freq;
+ sc->tc.tc_name = "MIPS32";
+ sc->tc.tc_quality = 800;
+ sc->tc.tc_priv = sc;
+ tc_init(&sc->tc);
+ sc->et.et_name = "MIPS32";
+ sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
+ ET_FLAGS_PERCPU;
+ sc->et.et_quality = 800;
+ sc->et.et_frequency = counter_freq;
+ sc->et.et_min_period.sec = 0;
+ sc->et.et_min_period.frac = 0x00004000LLU << 32;
+ sc->et.et_max_period.sec = 0xfffffffeU / sc->et.et_frequency;
+ sc->et.et_max_period.frac =
+ ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32;
+ sc->et.et_start = clock_start;
+ sc->et.et_stop = clock_stop;
+ sc->et.et_priv = sc;
+ et_register(&sc->et);
return (0);
}
@@ -373,7 +375,9 @@ static device_method_t clock_methods[] = {
};
static driver_t clock_driver = {
- "clock", clock_methods, 32
+ "clock",
+ clock_methods,
+ sizeof(struct clock_softc),
};
static devclass_t clock_devclass;
OpenPOWER on IntegriCloud