Author: neel
Date: Wed Mar 24 04:52:15 2010
New Revision: 205576
URL: http://svn.freebsd.org/changeset/base/205576

Log:
  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.

Modified:
  head/sys/mips/mips/tick.c

Modified: head/sys/mips/mips/tick.c
==============================================================================
--- head/sys/mips/mips/tick.c   Wed Mar 24 04:37:19 2010        (r205575)
+++ head/sys/mips/mips/tick.c   Wed Mar 24 04:52:15 2010        (r205576)
@@ -63,17 +63,14 @@ static uint64_t cycles_per_hz, cycles_pe
 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)
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to