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