summaryrefslogtreecommitdiffstats
path: root/arch/mips/sgi/kernel/indy_timer.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-11 15:21:44 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-11 15:21:44 +0000
commit6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (patch)
treefe544bf249c9093fdb94ea1bdf0a2af1acd3659e /arch/mips/sgi/kernel/indy_timer.c
parentc76e7d2fb3e85821ba1842d4f5219283eb706544 (diff)
Timer code rework. Done so far:
o Fix interrupt handler to not loose cycles o Warn about lost interrupts. o Fix calibration of the R4000 CPU timer. Still to do: o General cleanup of the timer code o Microsecond timers for the Indy o The calculated values for r4k_offset are still off by ~480 from the theoretical values. That means we're going to loose about 46 s per day. Are the crystals that bad or is there still a bug hidden somewhere? Maybe an option to set r4k_offset to a user supplied value might help? o Handle lost interrupts more gently so we don't loose time. o Handle 100MHz R4000 count / compare bug.
Diffstat (limited to 'arch/mips/sgi/kernel/indy_timer.c')
-rw-r--r--arch/mips/sgi/kernel/indy_timer.c34
1 files changed, 18 insertions, 16 deletions
diff --git a/arch/mips/sgi/kernel/indy_timer.c b/arch/mips/sgi/kernel/indy_timer.c
index 4b7bfd941..69b5ea062 100644
--- a/arch/mips/sgi/kernel/indy_timer.c
+++ b/arch/mips/sgi/kernel/indy_timer.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: indy_timer.c,v 1.3 1997/08/11 04:37:09 ralf Exp $
+ * $Id: indy_timer.c,v 1.4 1997/12/01 17:57:38 ralf Exp $
*/
#include <linux/errno.h>
@@ -101,10 +101,18 @@ static long last_rtc_update = 0;
void indy_timer_interrupt(struct pt_regs *regs)
{
+ unsigned long count;
int irq = 7;
/* Ack timer and compute new compare. */
- r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
+ count = read_32bit_cp0_register(CP0_COUNT);
+ if ((count - r4k_cur) >= r4k_offset) {
+ printk("missed heartbeat: r4k_cur[0x%lx] count[0x%lx]\n",
+ r4k_cur, count);
+ r4k_cur = count + r4k_offset;
+ }
+ else
+ r4k_cur += r4k_offset;
ack_r4ktimer(r4k_cur);
kstat.interrupts[irq]++;
do_timer(regs);
@@ -123,8 +131,8 @@ void indy_timer_interrupt(struct pt_regs *regs)
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
}
-static inline unsigned long dosample(volatile unsigned char *tcwp,
- volatile unsigned char *tc2p)
+static unsigned long dosample(volatile unsigned char *tcwp,
+ volatile unsigned char *tc2p)
{
unsigned long ct0, ct1;
unsigned char msb, lsb;
@@ -138,16 +146,12 @@ static inline unsigned long dosample(volatile unsigned char *tcwp,
ct0 = read_32bit_cp0_register(CP0_COUNT);
/* Latch and spin until top byte of counter2 is zero */
- *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT);
- ct1 = read_32bit_cp0_register(CP0_COUNT);
- lsb = *tc2p;
- msb = *tc2p;
- while(msb) {
+ do {
*tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT);
- ct1 = read_32bit_cp0_register(CP0_COUNT);
lsb = *tc2p;
msb = *tc2p;
- }
+ ct1 = read_32bit_cp0_register(CP0_COUNT);
+ } while(msb);
/* Stop the counter. */
*tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST);
@@ -254,11 +258,9 @@ void indy_timer_init(void)
tc2p = &p->tcnt2;
printk("calculating r4koff... ");
- r4k_offset = dosample(tcwp, tc2p); /* First sample. */
- dosample(tcwp, tc2p); /* Eat one... */
- r4k_offset += dosample(tcwp, tc2p); /* Second sample. */
- r4k_offset = (r4k_offset >> 1); /* Get average. */
- r4k_offset = HZ * r4k_offset; /* Multiply by HZ */
+ dosample(tcwp, tc2p); /* First sample. */
+ dosample(tcwp, tc2p); /* Eat one. */
+ r4k_offset = dosample(tcwp, tc2p); /* Second sample. */
printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);