summaryrefslogtreecommitdiffstats
path: root/sys/mips/mips/tick.c
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2010-05-27 01:27:25 +0000
committerneel <neel@FreeBSD.org>2010-05-27 01:27:25 +0000
commit24a8b9692fb6bf640d0b0d36774ebc871ad94410 (patch)
tree52c607d2dcc00d30cb6586056d52b93a2d5ef879 /sys/mips/mips/tick.c
parent39b696507f1a5623910a10e31faedf7281e3cc41 (diff)
downloadFreeBSD-src-24a8b9692fb6bf640d0b0d36774ebc871ad94410.zip
FreeBSD-src-24a8b9692fb6bf640d0b0d36774ebc871ad94410.tar.gz
Simplify clock interrupt handling on mips by using the new KPI - timer1clock()
and timer2clock(). Dynamically adjust the tick frequency depending on the value of 'hz'. Tested with hz values of 100, 1000 and 2000.
Diffstat (limited to 'sys/mips/mips/tick.c')
-rw-r--r--sys/mips/mips/tick.c105
1 files changed, 35 insertions, 70 deletions
diff --git a/sys/mips/mips/tick.c b/sys/mips/mips/tick.c
index 5931a5b..51270b4 100644
--- a/sys/mips/mips/tick.c
+++ b/sys/mips/mips/tick.c
@@ -58,19 +58,12 @@ struct timecounter *platform_timecounter;
static uint64_t cycles_per_tick;
static uint64_t cycles_per_usec;
-static uint64_t cycles_per_hz, cycles_per_stathz, cycles_per_profhz;
static u_int32_t counter_upper = 0;
static u_int32_t counter_lower_last = 0;
-struct clk_ticks {
- u_long hard_ticks;
- u_long stat_ticks;
- u_long prof_ticks;
- uint32_t compare_ticks;
-} __aligned(CACHE_LINE_SIZE);
-
-static struct clk_ticks pcpu_ticks[MAXCPU];
+static DPCPU_DEFINE(uint32_t, compare_ticks);
+static DPCPU_DEFINE(uint32_t, lost_ticks);
/*
* Device methods
@@ -150,22 +143,23 @@ mips_timer_init_params(uint64_t platform_counter_freq, int double_count)
if (double_count != 0)
counter_freq /= 2;
- cycles_per_tick = counter_freq / 1000;
- cycles_per_hz = counter_freq / hz;
- cycles_per_stathz = counter_freq / stathz;
- cycles_per_profhz = counter_freq / profhz;
+ if (hz >= 1500)
+ timer1hz = hz;
+ else if (hz >= 750)
+ timer1hz = hz * 2;
+ else
+ timer1hz = hz * 4;
+
+ cycles_per_tick = counter_freq / timer1hz;
cycles_per_usec = counter_freq / (1 * 1000 * 1000);
counter_timecounter.tc_frequency = counter_freq;
- printf("hz=%d cyl_per_tick:%jd cyl_per_usec:%jd freq:%jd "
- "cyl_per_hz:%jd cyl_per_stathz:%jd cyl_per_profhz:%jd\n",
+ 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,
- cycles_per_hz,
- cycles_per_stathz,
- cycles_per_profhz);
+ counter_freq);
set_cputicker(tick_ticker, counter_freq, 1);
}
@@ -243,58 +237,59 @@ DELAY(int n)
}
}
-#if 0 /* TARGET_OCTEON */
-int64_t wheel_run = 0;
-
-void octeon_led_run_wheel();
-
-#endif
/*
* Device section of file below
*/
static int
clock_intr(void *arg)
{
- struct clk_ticks *cpu_ticks;
struct trapframe *tf;
- uint32_t count, compare, delta;
-
- cpu_ticks = &pcpu_ticks[PCPU_GET(cpuid)];
+ uint32_t count, compare_last, compare_next, lost_ticks;
/*
* Set next clock edge.
*/
count = mips_rd_count();
- compare = cpu_ticks->compare_ticks;
- cpu_ticks->compare_ticks = count + cycles_per_tick;
- mips_wr_compare(cpu_ticks->compare_ticks);
+ compare_last = DPCPU_GET(compare_ticks);
+ compare_next = count + cycles_per_tick;
+ DPCPU_SET(compare_ticks, compare_next);
+ mips_wr_compare(compare_next);
+
critical_enter();
if (count < counter_lower_last) {
counter_upper++;
counter_lower_last = count;
}
+
/*
* Magic. Setting up with an arg of NULL means we get passed tf.
*/
tf = (struct trapframe *)arg;
- delta = cycles_per_tick;
-
/*
* Account for the "lost time" between when the timer interrupt fired
* and when 'clock_intr' actually started executing.
*/
- delta += count - compare;
+ 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 'delta'.
+ * up some reasonable value for the 'lost_ticks'.
*
* This could happen, for e.g., after we resume normal operations after
* exiting the debugger.
*/
- if (delta > cycles_per_hz)
- delta = cycles_per_hz;
+ if (lost_ticks > 2 * cycles_per_tick)
+ lost_ticks = cycles_per_tick;
+
+ while (lost_ticks >= cycles_per_tick) {
+ timer1clock(TRAPF_USERMODE(tf), tf->pc);
+ timer2clock(TRAPF_USERMODE(tf), tf->pc);
+ lost_ticks -= cycles_per_tick;
+ }
+ DPCPU_SET(lost_ticks, lost_ticks);
+
#ifdef KDTRACE_HOOKS
/*
* If the DTrace hooks are configured and a callback function
@@ -305,39 +300,9 @@ clock_intr(void *arg)
if (cyclic_clock_func[cpu] != NULL)
(*cyclic_clock_func[cpu])(tf);
#endif
- /* Fire hardclock at hz. */
- cpu_ticks->hard_ticks += delta;
- if (cpu_ticks->hard_ticks >= cycles_per_hz) {
- cpu_ticks->hard_ticks -= cycles_per_hz;
- if (PCPU_GET(cpuid) == 0)
- hardclock(TRAPF_USERMODE(tf), tf->pc);
- else
- hardclock_cpu(TRAPF_USERMODE(tf));
- }
-
- /* Fire statclock at stathz. */
- cpu_ticks->stat_ticks += delta;
- if (cpu_ticks->stat_ticks >= cycles_per_stathz) {
- cpu_ticks->stat_ticks -= cycles_per_stathz;
- statclock(TRAPF_USERMODE(tf));
- }
-
- /* Fire profclock at profhz, but only when needed. */
- cpu_ticks->prof_ticks += delta;
- if (cpu_ticks->prof_ticks >= cycles_per_profhz) {
- cpu_ticks->prof_ticks -= cycles_per_profhz;
- if (profprocs != 0)
- profclock(TRAPF_USERMODE(tf), tf->pc);
- }
+ timer1clock(TRAPF_USERMODE(tf), tf->pc);
+ timer2clock(TRAPF_USERMODE(tf), tf->pc);
critical_exit();
-#if 0 /* TARGET_OCTEON */
- /* Run the FreeBSD display once every hz ticks */
- wheel_run += cycles_per_tick;
- if (wheel_run >= cycles_per_usec * 1000000ULL) {
- wheel_run = 0;
- octeon_led_run_wheel();
- }
-#endif
return (FILTER_HANDLED);
}
OpenPOWER on IntegriCloud