Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/sgimips/sgimips Fix up clock interrupt accounting f...



details:   https://anonhg.NetBSD.org/src/rev/c363c95c4a33
branches:  trunk
changeset: 526388:c363c95c4a33
user:      rafal <rafal%NetBSD.org@localhost>
date:      Fri May 03 01:13:54 2002 +0000

description:
Fix up clock interrupt accounting for the sgimips port -- make sure
to schedule clock interrupts at a fixed interval, rather scheduling
the next one based on the time of the arrival/servicing of the previous
clock interrupt.  Also, pick up a trick from the sbmips port to convert
a division in ip22_clkread to a multiplication, since those are much
cheaper -- the details of that are described in Simon's commit (see
Message-Id: <20020306073437.1D2A8B004%cvs.netbsd.org@localhost>).  Thanks to
Jason Thorpe and Dominic Sweetman's "See MIPS Run" (where I found
mention of this very subject while looking for something totally un-
related! 8-) for the clue about the source of the timekeeping problems.

For the IP32, where we have no clock-calibration code yet, use the CPU
frequency provided by ARCS instead; it beats a hard-coded value!

As an added bonus, most of the CPU-clock related stuff is now collected
together in cpu_info_store, rather than as a collection of unorganized
global variables.

diffstat:

 sys/arch/sgimips/sgimips/clock.c   |  19 +++++++++-
 sys/arch/sgimips/sgimips/ip22.c    |  67 +++++++++++++++++++++++++++++--------
 sys/arch/sgimips/sgimips/ip32.c    |  57 ++++++++++++++++++++++++++++---
 sys/arch/sgimips/sgimips/machdep.c |  21 ++++++-----
 4 files changed, 131 insertions(+), 33 deletions(-)

diffs (truncated from 332 to 300 lines):

diff -r 6f093066f803 -r c363c95c4a33 sys/arch/sgimips/sgimips/clock.c
--- a/sys/arch/sgimips/sgimips/clock.c  Fri May 03 00:35:14 2002 +0000
+++ b/sys/arch/sgimips/sgimips/clock.c  Fri May 03 01:13:54 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: clock.c,v 1.4 2002/03/13 13:12:29 simonb Exp $ */
+/*     $NetBSD: clock.c,v 1.5 2002/05/03 01:13:54 rafal Exp $  */
 
 /*
  * Copyright (c) 1988 University of Utah.
@@ -48,11 +48,14 @@
 #include <sys/kernel.h>
 #include <sys/systm.h>
 
+#include <mips/locore.h>
 #include <dev/clock_subr.h>
 #include <sgimips/sgimips/clockvar.h>
 
 #define MINYEAR 2001 /* "today" */
 
+extern u_int32_t next_clk_intr;
+
 static struct device *clockdev;
 static const struct clockfns *clockfns;
 static int clockinitted;
@@ -103,10 +106,22 @@
 void
 cpu_initclocks()
 {
-
        if (clockfns == NULL)
                panic("cpu_initclocks: clock device not attached");
 
+       next_clk_intr = mips3_cp0_count_read() + curcpu()->ci_cycles_per_hz;
+       mips3_cp0_compare_write(next_clk_intr);
+
+       tick = 1000000 / hz;    /* number of microseconds between interrupts */
+       tickfix = 1000000 - (hz * tick);
+       if (tickfix) {
+               int ftp;
+
+               ftp = min(ffs(tickfix), ffs(hz));
+               tickfix >>= (ftp - 1);
+               tickfixinterval = hz >> (ftp - 1);
+        }
+
        (*clockfns->cf_init)(clockdev);
 }
 
diff -r 6f093066f803 -r c363c95c4a33 sys/arch/sgimips/sgimips/ip22.c
--- a/sys/arch/sgimips/sgimips/ip22.c   Fri May 03 00:35:14 2002 +0000
+++ b/sys/arch/sgimips/sgimips/ip22.c   Fri May 03 01:13:54 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip22.c,v 1.10 2002/05/02 18:00:40 rafal Exp $  */
+/*     $NetBSD: ip22.c,v 1.11 2002/05/03 01:13:55 rafal Exp $  */
 
 /*
  * Copyright (c) 2001 Rafal K. Boni
@@ -44,6 +44,10 @@
 
 #include <mips/cache.h>
 
+u_int32_t next_clk_intr;
+u_int32_t missed_clk_intrs;
+static unsigned long last_clk_intr;
+
 static struct evcnt mips_int5_evcnt =
     EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "mips", "int 5 (clock)");
 
@@ -53,12 +57,6 @@
 static u_int32_t iocwrite;     /* IOC write register: read-only */
 static u_int32_t iocreset;     /* IOC reset register: read-only */
 
-static unsigned long last_clk_intr;
-
-static unsigned long ticks_per_hz;
-static unsigned long ticks_per_usec;
-
-
 void           ip22_init(void);
 void           ip22_bus_reset(void);
 int            ip22_local0_intr(void);
@@ -175,16 +173,36 @@
 
        printf("Timer calibration, got %lu cycles (%lu, %lu, %lu)\n", cps,
                                ctrdiff[0], ctrdiff[1], ctrdiff[2]);
-       printf("CPU clock speed = %lu.%02luMhz\n", (2 * cps) / (1000000 / hz),
-                                       ((2 * cps) % (1000000 / hz) / 100));
 
        platform.clkread = ip22_clkread;
 
-       ticks_per_hz = cps;
-       ticks_per_usec = cps * hz / 1000000;
+       /* Counter on R4k/R4400/R4600/R5k counts at half the CPU frequency */
+       curcpu()->ci_cpu_freq = 2 * cps * hz;
+       curcpu()->ci_cycles_per_hz = curcpu()->ci_cpu_freq / (2 * hz);
+       curcpu()->ci_divisor_delay = curcpu()->ci_cpu_freq / (2 * 1000000);
+
+        /*
+         * To implement a more accurate microtime using the CP0 COUNT
+         * register we need to divide that register by the number of
+         * cycles per MHz.  But...
+         *
+         * DIV and DIVU are expensive on MIPS (eg 75 clocks on the
+         * R4000).  MULT and MULTU are only 12 clocks on the same CPU.  
+         *
+         * The strategy we use to to calculate the reciprical of cycles
+         * per MHz, scaled by 1<<32.  Then we can simply issue a MULTU
+         * and pluck of the HI register and have the results of the
+         * division.
+         */
+        curcpu()->ci_divisor_recip =
+            0x100000000ULL / curcpu()->ci_divisor_delay;
 
        evcnt_attach_static(&mips_int5_evcnt);
        evcnt_attach_static(&mips_spurint_evcnt);
+
+       printf("CPU clock speed = %lu.%02luMhz\n", 
+                               curcpu()->ci_cpu_freq / 1000000,
+                               (curcpu()->ci_cpu_freq / 10000) % 100);
 }
 
 void
@@ -205,6 +223,7 @@
        u_int32_t pc;
        u_int32_t ipending;
 {
+       u_int32_t newcnt;
        struct clockframe cf;
 
        /* Tickle Indy/I2 MC watchdog timer */
@@ -212,7 +231,21 @@
 
        if (ipending & MIPS_INT_MASK_5) {
                last_clk_intr = mips3_cp0_count_read();
-               mips3_cp0_compare_write(last_clk_intr + ticks_per_hz);
+
+               next_clk_intr += curcpu()->ci_cycles_per_hz;
+               mips3_cp0_compare_write(next_clk_intr);
+               newcnt = mips3_cp0_count_read();
+
+               /* 
+                * Missed one or more clock interrupts, so let's start 
+                * counting again from the current value.
+                */
+               if ((next_clk_intr - newcnt) & 0x80000000) {
+                   missed_clk_intrs++;
+
+                   next_clk_intr = newcnt + curcpu()->ci_cycles_per_hz;
+                   mips3_cp0_compare_write(next_clk_intr);
+               }
 
                cf.pc = pc;
                cf.sr = status;
@@ -408,10 +441,14 @@
 unsigned long
 ip22_clkread(void)
 {
-       unsigned long diff = mips3_cp0_count_read();
+       uint32_t res, count;
+
+       count = mips3_cp0_count_read() - last_clk_intr;
 
-       diff -= last_clk_intr;
-       return (diff / ticks_per_usec);
+       asm volatile("multu %1,%2 ; mfhi %0"
+               : "=r"(res) : "r"(count), "r"(curcpu()->ci_divisor_recip));
+
+       return (res);
 }
 
 unsigned long
diff -r 6f093066f803 -r c363c95c4a33 sys/arch/sgimips/sgimips/ip32.c
--- a/sys/arch/sgimips/sgimips/ip32.c   Fri May 03 00:35:14 2002 +0000
+++ b/sys/arch/sgimips/sgimips/ip32.c   Fri May 03 01:13:54 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip32.c,v 1.8 2002/04/29 02:06:14 rafal Exp $   */
+/*     $NetBSD: ip32.c,v 1.9 2002/05/03 01:13:55 rafal Exp $   */
 
 /*
  * Copyright (c) 2000 Soren S. Jorvang
@@ -52,21 +52,46 @@
 int    crime_intr(void *);
 void   *crime_intr_establish(int, int, int, int (*)(void *), void *);
 
+u_int32_t next_clk_intr;
+u_int32_t missed_clk_intrs;
+static unsigned long last_clk_intr;
+
 static struct evcnt mips_int5_evcnt =
     EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "mips", "int 5 (clock)");
 
 static struct evcnt mips_spurint_evcnt =
     EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "mips", "spurious interrupts");
 
-static unsigned long ticks_per_hz;
-
 void ip32_init(void)
 {
        /* XXXrkb: enable watchdog timer, clear it */
        *(volatile u_int32_t *)0xb400000c |= 0x200;
        *(volatile u_int32_t *)0xb4000034 = 0;
 
-       ticks_per_hz = 1000000;
+       /* 
+        * XXX: we have no clock calibration code for the IP32, so cpu speed
+        * is set from `cpuspeed' environment variable in machdep.c.
+        */
+       
+       /* Counter on R4k/R4400/R4600/R5k counts at half the CPU frequency */
+       curcpu()->ci_cycles_per_hz = curcpu()->ci_cpu_freq / (2 * hz);
+       curcpu()->ci_divisor_delay = curcpu()->ci_cpu_freq / (2 * 1000000);
+
+        /*
+         * To implement a more accurate microtime using the CP0 COUNT
+         * register we need to divide that register by the number of
+         * cycles per MHz.  But...
+         *
+         * DIV and DIVU are expensive on MIPS (eg 75 clocks on the
+         * R4000).  MULT and MULTU are only 12 clocks on the same CPU.  
+         *
+         * The strategy we use to to calculate the reciprical of cycles
+         * per MHz, scaled by 1<<32.  Then we can simply issue a MULTU
+         * and pluck of the HI register and have the results of the
+         * division.
+         */
+        curcpu()->ci_divisor_recip =
+            0x100000000ULL / curcpu()->ci_divisor_delay;
 
        platform.iointr = ip32_intr;
        platform.bus_reset = ip32_bus_reset;
@@ -79,6 +104,10 @@
 
        evcnt_attach_static(&mips_int5_evcnt);
        evcnt_attach_static(&mips_spurint_evcnt);
+
+       printf("CPU clock speed = %lu.%02luMhz\n", 
+                               curcpu()->ci_cpu_freq / 1000000,
+                               (curcpu()->ci_cpu_freq / 10000) % 100);
 }
 
 void
@@ -99,7 +128,7 @@
        u_int32_t ipending;
 {
        int i;
-       unsigned long cycles;
+       u_int32_t newcnt;
        struct clockframe cf;
 
 #if 0
@@ -129,8 +158,22 @@
 #endif
 
        if (ipending & MIPS_INT_MASK_5) {
-               cycles = mips3_cp0_count_read();
-               mips3_cp0_compare_write(cycles + ticks_per_hz);
+               last_clk_intr = mips3_cp0_count_read();
+
+               next_clk_intr += curcpu()->ci_cycles_per_hz;
+               mips3_cp0_compare_write(next_clk_intr);
+               newcnt = mips3_cp0_count_read();
+
+               /* 
+                * Missed one or more clock interrupts, so let's start 
+                * counting again from the current value.
+                */
+               if ((next_clk_intr - newcnt) & 0x80000000) {
+                   missed_clk_intrs++;
+
+                   next_clk_intr = newcnt + curcpu()->ci_cycles_per_hz;
+                   mips3_cp0_compare_write(next_clk_intr);
+               }
 
                cf.pc = pc;
                cf.sr = status;
diff -r 6f093066f803 -r c363c95c4a33 sys/arch/sgimips/sgimips/machdep.c
--- a/sys/arch/sgimips/sgimips/machdep.c        Fri May 03 00:35:14 2002 +0000
+++ b/sys/arch/sgimips/sgimips/machdep.c        Fri May 03 01:13:54 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: machdep.c,v 1.35 2002/04/29 02:06:14 rafal Exp $       */
+/*     $NetBSD: machdep.c,v 1.36 2002/05/03 01:13:55 rafal Exp $       */
 
 /*
  * Copyright (c) 2000 Soren S. Jorvang
@@ -35,6 +35,7 @@
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
 #include "opt_execfmt.h"
+#include "opt_cputype.h"
 #include "opt_machtypes.h"
 
 #include <sys/param.h>
@@ -97,8 +98,6 @@
 /* Our exported CPU info; we can have only one. */
 struct cpu_info cpu_info_store;
 
-unsigned long cpuspeed;        /* Approximate number of instructions per usec */
-
 /* Maps for VM objects. */
 struct vm_map *exec_map = NULL;



Home | Main Index | Thread Index | Old Index