patch-2.1.44 linux/arch/mips/kernel/time.c
Next file: linux/arch/mips/kernel/traps.c
Previous file: linux/arch/mips/kernel/sysmips.c
Back to the patch index
Back to the overall index
- Lines: 209
- Date:
Mon Jul 7 08:18:54 1997
- Orig file:
v2.1.43/linux/arch/mips/kernel/time.c
- Orig date:
Mon May 6 02:26:03 1996
diff -u --recursive --new-file v2.1.43/linux/arch/mips/kernel/time.c linux/arch/mips/kernel/time.c
@@ -5,21 +5,30 @@
*
* This file contains the time handling details for PC-style clocks as
* found in some MIPS systems.
+ *
+ * $Id: time.c,v 1.4 1997/06/30 15:52:40 ralf Exp $
*/
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/interrupt.h>
-#include <asm/segment.h>
+#include <asm/bootinfo.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <linux/mc146818rtc.h>
#include <linux/timex.h>
-#define TIMER_IRQ 0
+extern volatile unsigned long lost_ticks;
+
+/* change this if you have some constant time drift */
+#define USECS_PER_JIFFY (1000020/HZ)
/* This function must be called with interrupts disabled
* It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
@@ -58,22 +67,64 @@
static unsigned long do_slow_gettimeoffset(void)
{
int count;
- unsigned long offset = 0;
+
+ static int count_p = LATCH; /* for the first call after boot */
+ static unsigned long jiffies_p = 0;
+
+ /*
+ * cache volatile jiffies temporarily; we have IRQs turned off.
+ */
+ unsigned long jiffies_t;
/* timer count may underflow right here */
outb_p(0x00, 0x43); /* latch the count ASAP */
+
count = inb_p(0x40); /* read the latched count */
- count |= inb(0x40) << 8;
- /* we know probability of underflow is always MUCH less than 1% */
- if (count > (LATCH - LATCH/100)) {
- /* check for pending timer interrupt */
- outb_p(0x0a, 0x20);
- if (inb(0x20) & 1)
- offset = TICK_SIZE;
- }
+
+ /*
+ * We do this guaranteed double memory access instead of a _p
+ * postfix in the previous port access. Wheee, hackady hack
+ */
+ jiffies_t = jiffies;
+
+ count |= inb_p(0x40) << 8;
+
+ /*
+ * avoiding timer inconsistencies (they are rare, but they happen)...
+ * there are two kinds of problems that must be avoided here:
+ * 1. the timer counter underflows
+ * 2. hardware problem with the timer, not giving us continuous time,
+ * the counter does small "jumps" upwards on some Pentium systems,
+ * (see c't 95/10 page 335 for Neptun bug.)
+ */
+
+ if( jiffies_t == jiffies_p ) {
+ if( count > count_p ) {
+ /* the nutcase */
+
+ outb_p(0x0A, 0x20);
+
+ /* assumption about timer being IRQ1 */
+ if( inb(0x20) & 0x01 ) {
+ /*
+ * We cannot detect lost timer interrupts ...
+ * well, thats why we call them lost, dont we? :)
+ * [hmm, on the Pentium and Alpha we can ... sort of]
+ */
+ count -= LATCH;
+ } else {
+ printk("do_slow_gettimeoffset(): hardware timer problem?\n");
+ }
+ }
+ } else
+ jiffies_p = jiffies_t;
+
+ count_p = count;
+
count = ((LATCH-1) - count) * TICK_SIZE;
count = (count + LATCH/2) / LATCH;
- return offset + count;
+
+ return count;
}
static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
@@ -85,15 +136,23 @@
{
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
*tv = xtime;
tv->tv_usec += do_gettimeoffset();
+
+ /*
+ * xtime is atomically updated in timer_bh. lost_ticks is
+ * nonzero if the timer bottom half hasnt executed yet.
+ */
+ if (lost_ticks)
+ tv->tv_usec += USECS_PER_JIFFY;
+
+ restore_flags(flags);
+
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
}
- restore_flags(flags);
}
void do_settimeofday(struct timeval *tv)
@@ -114,8 +173,8 @@
xtime = *tv;
time_state = TIME_BAD;
- time_maxerror = 0x70000000;
- time_esterror = 0x70000000;
+ time_maxerror = MAXPHASE;
+ time_esterror = MAXPHASE;
sti();
}
@@ -166,7 +225,7 @@
/* The following flags have to be released exactly in this order,
* otherwise the DS12887 (popular MC146818A clone with integrated
- * battery and crystal) will not reset the oscillator and will not
+ * battery and quartz) will not reset the oscillator and will not
* update precisely 500 ms later. You won't find this mentioned in
* the Dallas Semiconductor data sheets, but who believes data
* sheets anyway ... -- Markus Kuhn
@@ -184,7 +243,7 @@
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-static void timer_interrupt(int irq, struct pt_regs * regs)
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
do_timer(regs);
@@ -204,7 +263,7 @@
basically because we don't yet share IRQ's around. This message is
rigged to be safe on the 386 - basically it's a hack, so don't look
closely for now.. */
- smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0);
+ /*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */
}
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -238,9 +297,12 @@
)*60 + sec; /* finally seconds */
}
-void time_init(void)
+static struct irqaction irq0 = { timer_interrupt, 0, 0, "timer", NULL, NULL};
+
+void (*board_time_init)(struct irqaction *irq);
+
+__initfunc(void time_init(void))
{
- void (*irq_handler)(int, struct pt_regs *);
unsigned int year, mon, day, hour, min, sec;
int i;
@@ -273,14 +335,16 @@
BCD_TO_BIN(mon);
BCD_TO_BIN(year);
}
+#if 0 /* the IBM way */
if ((year += 1900) < 1970)
year += 100;
+#else
+ /* Acer PICA clock starts from 1980. True for all MIPS machines? */
+ year += 1980;
+#endif
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_usec = 0;
/* FIXME: If we have the CPU hardware time counters, use them */
- irq_handler = timer_interrupt;
-
- if (request_irq(TIMER_IRQ, irq_handler, 0, "timer") != 0)
- panic("Could not allocate timer IRQ!");
+ board_time_init(&irq0);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov