summaryrefslogtreecommitdiffstats
path: root/sys/mips
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2010-03-24 04:52:15 +0000
committerneel <neel@FreeBSD.org>2010-03-24 04:52:15 +0000
commit3f8aee1ae510ea3ad4700cbde1bafe934feb7558 (patch)
treed9731e9a4a3ee467f25e546e73452075b391ffb5 /sys/mips
parent32325226c5ca5fed0d19cc1a6a94ae7e43675a4c (diff)
downloadFreeBSD-src-3f8aee1ae510ea3ad4700cbde1bafe934feb7558.zip
FreeBSD-src-3f8aee1ae510ea3ad4700cbde1bafe934feb7558.tar.gz
Fix periodic "t_delta 16.01359db7eb5eb3c0 too long" messages on the console by
accounting for the "lost time" between when the timer interrupt fired and when clock_intr() actually started executing.
Diffstat (limited to 'sys/mips')
-rw-r--r--sys/mips/mips/tick.c53
1 files changed, 36 insertions, 17 deletions
diff --git a/sys/mips/mips/tick.c b/sys/mips/mips/tick.c
index b83d83f..60b3511 100644
--- a/sys/mips/mips/tick.c
+++ b/sys/mips/mips/tick.c
@@ -63,17 +63,14 @@ 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
-{
+struct clk_ticks {
u_long hard_ticks;
u_long stat_ticks;
u_long prof_ticks;
- /*
- * pad for cache line alignment of pcpu info
- * cache-line-size - number of used bytes
- */
- char pad[32-(3*sizeof (u_long))];
-} static pcpu_ticks[MAXCPU];
+ uint32_t compare_ticks;
+} __aligned(CACHE_LINE_SIZE);
+
+static struct clk_ticks pcpu_ticks[MAXCPU];
/*
* Device methods
@@ -260,25 +257,47 @@ clock_intr(void *arg)
{
struct clk_ticks *cpu_ticks;
struct trapframe *tf;
- uint32_t ltick;
+ uint32_t count, compare, delta;
+
+ cpu_ticks = &pcpu_ticks[PCPU_GET(cpuid)];
+
/*
* Set next clock edge.
*/
- ltick = mips_rd_count();
- mips_wr_compare(ltick + cycles_per_tick);
- cpu_ticks = &pcpu_ticks[PCPU_GET(cpuid)];
+ count = mips_rd_count();
+ compare = cpu_ticks->compare_ticks;
+ cpu_ticks->compare_ticks = count + cycles_per_tick;
+ mips_wr_compare(cpu_ticks->compare_ticks);
critical_enter();
- if (ltick < counter_lower_last) {
+ if (count < counter_lower_last) {
counter_upper++;
- counter_lower_last = ltick;
+ 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;
+
+ /*
+ * If the COUNT and COMPARE registers are no longer in sync then make
+ * up some reasonable value for the 'delta'.
+ *
+ * This could happen, for e.g., after we resume normal operations after
+ * exiting the debugger.
+ */
+ if (delta > cycles_per_hz)
+ delta = cycles_per_hz;
+
/* Fire hardclock at hz. */
- cpu_ticks->hard_ticks += cycles_per_tick;
+ 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)
@@ -288,14 +307,14 @@ clock_intr(void *arg)
}
/* Fire statclock at stathz. */
- cpu_ticks->stat_ticks += cycles_per_tick;
+ cpu_ticks->stat_ticks += delta;
if (cpu_ticks->stat_ticks >= cycles_per_stathz) {
cpu_ticks->stat_ticks -= cycles_per_stathz;
statclock(USERMODE(tf->sr));
}
/* Fire profclock at profhz, but only when needed. */
- cpu_ticks->prof_ticks += cycles_per_tick;
+ cpu_ticks->prof_ticks += delta;
if (cpu_ticks->prof_ticks >= cycles_per_profhz) {
cpu_ticks->prof_ticks -= cycles_per_profhz;
if (profprocs != 0)
OpenPOWER on IntegriCloud