Subject: High resolution timer support for I/O ASIC DECstations

From: "Maciej W. Rozycki" <[email-masked]>
Date: Mon, 7 Aug 2000 17:22:54 +0200 (MET DST)

Hi,

 Following is a patch that implements a high resolution timer for I/O ASIC
DECstations, i.e. it provides a do_fast_gettimeoffset() function that is
suitable for R3K-based machines (that do not have a cycle counter within
the CPU).  Also a proper do_div() macro is included.  There are also a few
small cleanups and enhancements in the related code.

 This change makes my NTP daemon particularly happy -- a dispersion of
0.02 when synchronizing with a remote server is really nice.  An X server
would benefit, too, if we had one. 

 I'd like to encourage everyone interested to test these changes as much
as possible.  Also if anyone knows of a better division algorithm than the
one I used for do_div64_32(), I'd be glad to hear of it.  If nothing wrong
pops up, these changes should be included in the official tree, I believe. 

 Comments are welcomed, as usually.

  Maciej

-- 
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: [email-masked], PGP key available        +

diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/arch/mips/Makefile linux-mips-2.4.0-test5-20000731/arch/mips/Makefile
--- linux-mips-2.4.0-test5-20000731.macro/arch/mips/Makefile	Thu Jul 13 04:26:16 2000
+++ linux-mips-2.4.0-test5-20000731/arch/mips/Makefile	Sat Aug  5 17:45:33 2000
@@ -35,7 +35,7 @@
 # machines may also.  Since BFD is incredibly buggy with respect to
 # crossformat linking we rely on the elf2ecoff tool for format conversion.
 #
-CFLAGS		+= -G 0 -mno-abicalls -fno-pic
+GCCFLAGS	:= -G 0 -mno-abicalls -fno-pic
 LINKFLAGS	+= -static -G 0
 MODFLAGS	+= -mlong-calls
 
@@ -47,31 +47,40 @@
 # CPU-dependent compiler/assembler options for optimization.
 #
 ifdef CONFIG_CPU_R3000
-CFLAGS		:= $(CFLAGS) -mcpu=r3000 -mips1
+GCCFLAGS	+= -mcpu=r3000 -mips1
 endif
 ifdef CONFIG_CPU_R6000
-CFLAGS		:= $(CFLAGS) -mcpu=r6000 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r6000 -mips2 -Wa,--trap
 endif
 ifdef CONFIG_CPU_R4300
-CFLAGS		:= $(CFLAGS) -mcpu=r4300 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r4300 -mips2 -Wa,--trap
 endif
 ifdef CONFIG_CPU_R4X00
-CFLAGS		:= $(CFLAGS) -mcpu=r4600 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r4600 -mips2 -Wa,--trap
 endif
 ifdef CONFIG_CPU_R5000
-CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r8000 -mips2 -Wa,--trap
 endif
 ifdef CONFIG_CPU_NEVADA
-CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap -mmad
+GCCFLAGS	+= -mcpu=r8000 -mips2 -Wa,--trap -mmad
 endif
 ifdef CONFIG_CPU_R8000
-CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r8000 -mips2 -Wa,--trap
 endif
 ifdef CONFIG_CPU_R10000
-CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r8000 -mips2 -Wa,--trap
 endif
 
 #
+# The pipe options is bad for my low-mem machine
+# Uncomment this if you want this.
+#
+GCCFLAGS	+= -pipe
+
+CFLAGS		+= $(GCCFLAGS)
+AFLAGS		+= $(GCCFLAGS)
+
+#
 # Board-dependent options and extra files
 #
 ifdef CONFIG_ALGOR_P4032
@@ -168,12 +177,6 @@
 ifdef LOADADDR
 LINKFLAGS     += -Ttext $(word 1,$(LOADADDR))
 endif
-
-#
-# The pipe options is bad for my low-mem machine
-# Uncomment this if you want this.
-#
-CFLAGS		+= -pipe
 
 HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
 
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/arch/mips/dec/Makefile linux-mips-2.4.0-test5-20000731/arch/mips/dec/Makefile
--- linux-mips-2.4.0-test5-20000731.macro/arch/mips/dec/Makefile	Tue Mar 28 04:26:06 2000
+++ linux-mips-2.4.0-test5-20000731/arch/mips/dec/Makefile	Sat Aug  5 17:24:35 2000
@@ -7,9 +7,9 @@
 #
 
 .S.s:
-	$(CPP) $(CFLAGS) $< -o $*.s
+	$(CPP) $(AFLAGS) -traditional -o $*.o $<
 .S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
+	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
 
 all: dec.o
 O_TARGET := dec.o
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/arch/mips/dec/int-handler.S linux-mips-2.4.0-test5-20000731/arch/mips/dec/int-handler.S
--- linux-mips-2.4.0-test5-20000731.macro/arch/mips/dec/int-handler.S	Tue Mar 28 04:26:06 2000
+++ linux-mips-2.4.0-test5-20000731/arch/mips/dec/int-handler.S	Sat Aug  5 15:31:37 2000
@@ -2,6 +2,7 @@
  * arch/mips/dec/int-handler.S
  *
  * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen
+ * Copyright (C) 2000  Maciej W. Rozycki
  *
  * Written by Ralf Baechle and Andreas Busse, modified for DECStation
  * support by Paul Antoine and Harald Koerfgen.
@@ -16,6 +17,11 @@
 #include <asm/stackframe.h>
 #include <asm/addrspace.h>
 
+#include <asm/dec/kn01.h>
+#include <asm/dec/kn02.h>
+#include <asm/dec/kn02xa.h>
+#include <asm/dec/kn03.h>
+#include <asm/dec/ioasic_addrs.h>
 #include <asm/dec/interrupts.h>

@@ -164,10 +170,10 @@
 /*
  * Handle "IRQ Controller" Interrupts
  * Masked Interrupts are still visible and have to be masked "by hand".
- * %hi(KN02_CSR_ADDR) does not work so all addresses are hardcoded :-(.
  */
 		EXPORT(kn02_io_int)
-kn02_io_int:	lui	t0,0xbff0		# get interrupt status and mask
+kn02_io_int:					# 3max
+		lui	t0,KN02_CSR_ADDR>>16	# get interrupt status and mask
 		lw	t0,(t0)
 		la	t1,asic_mask_tbl
 		move	t3,t0
@@ -176,17 +182,20 @@
 		 and	t0,t3			# mask out allowed ones
 
 		EXPORT(kn03_io_int)
-kn03_io_int:	lui	t2,0xbf84		# upper part of IOASIC Address
-		lw	t0,0x0110(t2)		# get status: IOASIC isr
-		lw	t3,0x0120(t2)		# get mask:   IOASIC isrm
+kn03_io_int:					# 3max+
+		lui	t2,KN03_IOASIC_BASE>>16	# upper part of IOASIC Address
+		lw	t0,SIR(t2)		# get status: IOASIC isr
+		lw	t3,SIMR(t2)		# get mask:   IOASIC isrm
 		la	t1,asic_mask_tbl
 		b	find_int
 		 and	t0,t3			# mask out allowed ones
 
-		EXPORT(kn02ba_io_int)
-kn02ba_io_int:	lui	t2,0xbc04		
-		lw	t0,0x0110(t2)		# IOASIC isr, works for maxine also
-		lw	t3,0x0120(t2)		# IOASIC isrm
+		EXPORT(kn02xa_io_int)
+kn02xa_io_int:					# 3min/maxine
+		lui	t2,KN02XA_IOASIC_BASE>>16		
+						# upper part of IOASIC Address
+		lw	t0,SIR(t2)		# get status: IOASIC isr
+		lw	t3,SIMR(t2)		# get mask:   IOASIC isrm
 		la	t1,asic_mask_tbl
 		and	t0,t3
 
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/arch/mips/dec/irq.c linux-mips-2.4.0-test5-20000731/arch/mips/dec/irq.c
--- linux-mips-2.4.0-test5-20000731.macro/arch/mips/dec/irq.c	Tue Mar 28 04:26:06 2000
+++ linux-mips-2.4.0-test5-20000731/arch/mips/dec/irq.c	Sat Aug  5 18:40:27 2000
@@ -27,10 +27,6 @@
 
 #include <asm/dec/interrupts.h>
 
-extern volatile unsigned int *isr;	/* address of the interrupt status register     */
-extern volatile unsigned int *imr;	/* address of the interrupt mask register       */
-extern decint_t dec_interrupt[NR_INTS];
-
 irq_cpustat_t irq_stat [NR_CPUS];
 
 unsigned int local_bh_count[NR_CPUS];
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/arch/mips/dec/setup.c linux-mips-2.4.0-test5-20000731/arch/mips/dec/setup.c
--- linux-mips-2.4.0-test5-20000731.macro/arch/mips/dec/setup.c	Tue Mar 28 04:26:06 2000
+++ linux-mips-2.4.0-test5-20000731/arch/mips/dec/setup.c	Sat Aug  5 18:49:00 2000
@@ -6,6 +6,7 @@
  * for more details.
  *
  * Copyright (C) 1998 Harald Koerfgen
+ * Copyright (C) 2000 Maciej W. Rozycki
  */
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -22,6 +23,8 @@
 #include <asm/dec/kn02.h>
 #include <asm/dec/kn02xa.h>
 #include <asm/dec/kn03.h>
+#include <asm/dec/ioasic.h>
+#include <asm/dec/ioasic_addrs.h>
 #include <asm/dec/ioasic_ints.h>
 
 extern asmlinkage void decstation_handle_int(void);
@@ -33,14 +36,14 @@
 void dec_init_kn02ca(void);
 void dec_init_kn03(void);
 
-char *dec_rtc_base = (char *) KN01_RTC_BASE;	/* Assume DS2100/3100 initially */
+char *dec_rtc_base = (void *) KN01_RTC_BASE;	/* Assume DS2100/3100 initially */
+
+volatile unsigned int *ioasic_base;
 
 decint_t dec_interrupt[NR_INTS];
 
-/* 
+/*
  * Information regarding the IRQ Controller
- *
- * isr and imr are also hardcoded for different machines in int_handler.S
  */
 
 volatile unsigned int *isr = 0L;	/* address of the interrupt status register     */
@@ -206,8 +209,8 @@
      * Setup some memory addresses. FIXME: probably incomplete!
      */
     dec_rtc_base = (char *) KN02_RTC_BASE;
-    isr = (volatile unsigned int *) KN02_CSR_ADDR;
-    imr = (volatile unsigned int *) KN02_CSR_ADDR;
+    isr = (void *) KN02_CSR_ADDR;
+    imr = (void *) KN02_CSR_ADDR;
 
     /*
      * Setup IOASIC interrupt
@@ -275,16 +278,17 @@
     /*
      * Setup some memory addresses.
      */
+    ioasic_base = (void *) KN02XA_IOASIC_BASE;
     dec_rtc_base = (char *) KN02XA_RTC_BASE;
-    isr = (volatile unsigned int *) KN02XA_SIR_ADDR;
-    imr = (volatile unsigned int *) KN02XA_SIRM_ADDR;
+    isr = (void *) KN02XA_IOASIC_REG(SIR);
+    imr = (void *) KN02XA_IOASIC_REG(SIMR);
 
     /*
      * Setup IOASIC interrupt
      */
     cpu_mask_tbl[0] = IE_IRQ3;
     cpu_irq_nr[0] = -1;
-    cpu_ivec_tbl[0] = kn02ba_io_int;
+    cpu_ivec_tbl[0] = kn02xa_io_int;
     *imr = 0;
 
     /*
@@ -355,14 +359,15 @@
     /*
      * Setup some memory addresses. FIXME: probably incomplete!
      */
+    ioasic_base = (void *) KN02XA_IOASIC_BASE;
     dec_rtc_base = (char *) KN02XA_RTC_BASE;
-    isr = (volatile unsigned int *) KN02XA_SIR_ADDR;
-    imr = (volatile unsigned int *) KN02XA_SIRM_ADDR;
+    isr = (void *) KN02XA_IOASIC_REG(SIR);
+    imr = (void *) KN02XA_IOASIC_REG(SIMR);
 
     /*
      * Setup IOASIC interrupt
      */
-    cpu_ivec_tbl[1] = kn02ba_io_int;
+    cpu_ivec_tbl[1] = kn02xa_io_int;
     cpu_irq_nr[1] = -1;
     cpu_mask_tbl[1] = IE_IRQ3;
     *imr = 0;
@@ -430,9 +435,10 @@
     /*
      * Setup some memory addresses. FIXME: probably incomplete!
      */
+    ioasic_base = (void *) KN03_IOASIC_BASE;
     dec_rtc_base = (char *) KN03_RTC_BASE;
-    isr = (volatile unsigned int *) KN03_SIR_ADDR;
-    imr = (volatile unsigned int *) KN03_SIRM_ADDR;
+    isr = (void *) KN03_IOASIC_REG(SIR);
+    imr = (void *) KN03_IOASIC_REG(SIMR);
 
     /*
      * Setup IOASIC interrupt
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/arch/mips/dec/time.c linux-mips-2.4.0-test5-20000731/arch/mips/dec/time.c
--- linux-mips-2.4.0-test5-20000731.macro/arch/mips/dec/time.c	Wed Jul 12 04:25:56 2000
+++ linux-mips-2.4.0-test5-20000731/arch/mips/dec/time.c	Sat Aug  5 19:19:57 2000
@@ -1,8 +1,9 @@
 
 /*
- *  linux/arch/mips/kernel/time.c
+ *  linux/arch/mips/dec/time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *  Copyright (C) 2000  Maciej W. Rozycki
  *
  * This file contains the time handling details for PC-style clocks as
  * found in some MIPS systems.
@@ -21,10 +22,15 @@
 #include <asm/mipsregs.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/ioasic.h>
+#include <asm/dec/ioasic_addrs.h>
 
 #include <linux/mc146818rtc.h>
 #include <linux/timex.h>
 
+#include <asm/div64.h>
+
 extern volatile unsigned long wall_jiffies;
 extern rwlock_t xtime_lock;
 
@@ -36,12 +42,22 @@
 
 /* This is for machines which generate the exact clock. */
 #define USECS_PER_JIFFY (1000000/HZ)
+#define USECS_PER_JIFFY_FRAC (0x100000000*1000000/HZ&0xffffffff)
 
 /* Cycle counter value at the previous timer interrupt.. */
 
 static unsigned int timerhi = 0, timerlo = 0;
 
 /*
+ * Cached "1/(clocks per usec)*2^32" value.
+ * It has to be recalculated once each jiffy.
+ */
+static unsigned long cached_quotient = 0;
+
+/* Last jiffy when do_fast_gettimeoffset() was called. */
+static unsigned long last_jiffies = 0;
+
+/*
  * On MIPS only R4000 and better have a cycle counter.
  *
  * FIXME: Does playing with the RP bit in c0_status interfere with this code?
@@ -50,45 +66,34 @@
 {
 	u32 count;
 	unsigned long res, tmp;
-
-	/* Last jiffy when do_fast_gettimeoffset() was called. */
-	static unsigned long last_jiffies = 0;
 	unsigned long quotient;
 
-	/*
-	 * Cached "1/(clocks per usec)*2^32" value.
-	 * It has to be recalculated once each jiffy.
-	 */
-	static unsigned long cached_quotient = 0;
-
 	tmp = jiffies;
 
 	quotient = cached_quotient;
 
-	if (tmp && last_jiffies != tmp) {
-		last_jiffies = tmp;
-		__asm__(".set\tnoreorder\n\t"
-			".set\tnoat\n\t"
-			".set\tmips3\n\t"
-			"lwu\t%0,%2\n\t"
-			"dsll32\t$1,%1,0\n\t"
-			"or\t$1,$1,%0\n\t"
-			"ddivu\t$0,$1,%3\n\t"
-			"mflo\t$1\n\t"
-			"dsll32\t%0,%4,0\n\t"
-			"nop\n\t"
-			"ddivu\t$0,%0,$1\n\t"
-			"mflo\t%0\n\t"
-			".set\tmips0\n\t"
-			".set\tat\n\t"
-			".set\treorder"
-			:"=&r"(quotient)
-			:"r"(timerhi),
-			"m"(timerlo),
-			"r"(tmp),
-			"r"(USECS_PER_JIFFY)
-			:"$1");
+	if (last_jiffies != tmp) {
+	    last_jiffies = tmp;
+	    if (last_jiffies != 0) {
+		unsigned long r0;
+		__asm__(".set	push\n\t"
+			".set	mips3\n\t"
+			"lwu	%0,%3\n\t"
+			"dsll32	%1,%2,0\n\t"
+			"or	%1,%1,%0\n\t"
+			"ddivu	$0,%1,%4\n\t"
+			"mflo	%1\n\t"
+			"dsll32	%0,%5,0\n\t"
+			"or	%0,%0,%6\n\t"
+			"ddivu	$0,%0,%1\n\t"
+			"mflo	%0\n\t"
+			".set	pop"
+			: "=&r" (quotient), "=&r" (r0)
+			: "r" (timerhi), "m" (timerlo),
+			  "r" (tmp), "r" (USECS_PER_JIFFY),
+			  "r" (USECS_PER_JIFFY_FRAC));
 		cached_quotient = quotient;
+	    }
 	}
 	/* Get last timer tick in absolute kernel time */
 	count = read_32bit_cp0_register(CP0_COUNT);
@@ -97,11 +102,9 @@
 	count -= timerlo;
 //printk("count: %08lx, %08lx:%08lx\n", count, timerhi, timerlo);
 
-	__asm__("multu\t%1,%2\n\t"
-		"mfhi\t%0"
-		:"=r"(res)
-		:"r"(count),
-		"r"(quotient));
+	__asm__("multu	%2,%3"
+		: "=l" (tmp), "=h" (res)
+		: "r" (count), "r" (quotient));
 
 	/*
 	 * Due to possible jiffies inconsistencies, we need to check 
@@ -113,6 +116,47 @@
 	return res;
 }
 
+static unsigned long do_ioasic_gettimeoffset(void)
+{
+	u32 count;
+	unsigned long res, tmp;
+	unsigned long quotient;
+
+	tmp = jiffies;
+
+	quotient = cached_quotient;
+
+	if (last_jiffies != tmp) {
+		last_jiffies = tmp;
+		if (last_jiffies != 0) {
+			unsigned long r0;
+			do_div64_32(r0, timerhi, timerlo, tmp);
+			do_div64_32(quotient, USECS_PER_JIFFY,
+				    USECS_PER_JIFFY_FRAC, r0);
+			cached_quotient = quotient;
+		}
+	}
+	/* Get last timer tick in absolute kernel time */
+	count = ioasic_read(FCTR);
+
+	/* .. relative to previous jiffy (32 bits is enough) */
+	count -= timerlo;
+//printk("count: %08x, %08x:%08x\n", count, timerhi, timerlo);
+
+	__asm__("multu	%2,%3"
+		: "=l" (tmp), "=h" (res)
+		: "r" (count), "r" (quotient));
+
+	/*
+	 * Due to possible jiffies inconsistencies, we need to check
+	 * the result so that we'll get a timer that is monotonic.
+	 */
+	if (res >= USECS_PER_JIFFY)
+        	res = USECS_PER_JIFFY - 1;
+
+	return res;
+}
+
 /* This function must be called with interrupts disabled 
  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
  * 
@@ -170,8 +214,8 @@
 	tv->tv_usec += do_gettimeoffset();
 
 	/*
-	 * xtime is atomically updated in timer_bh. lost_ticks is
-	 * nonzero if the timer bottom half hasnt executed yet.
+	 * xtime is atomically updated in timer_bh. jiffies - wall_jiffies
+	 * is nonzero if the timer bottom half hasnt executed yet.
 	 */
 	if (jiffies - wall_jiffies)
 		tv->tv_usec += USECS_PER_JIFFY;
@@ -309,11 +353,12 @@
 	read_lock(&xtime_lock);
 	if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
 	    xtime.tv_usec > 500000 - (tick >> 1) &&
-	    xtime.tv_usec < 500000 + (tick >> 1))
+	    xtime.tv_usec < 500000 + (tick >> 1)) {
 		if (set_rtc_mmss(xtime.tv_sec) == 0)
 			last_rtc_update = xtime.tv_sec;
 		else
 			last_rtc_update = xtime.tv_sec - 600;	/* do it again in 60 s */
+	}
 	/* As we return to user mode fire off the other CPU schedulers.. this is
 	   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
@@ -334,16 +379,42 @@
 	timerhi += (count < timerlo);	/* Wrap around */
 	timerlo = count;
 
+	if (jiffies == ~0) {
+		/*
+		 * If jiffies is to overflow in this timer_interrupt we must
+		 * update the timer[hi]/[lo] to make do_fast_gettimeoffset()
+		 * quotient calc still valid. -arca
+		 */
+		write_32bit_cp0_register(CP0_COUNT, 0);
+		timerhi = timerlo = 0;
+	}
+
 	timer_interrupt(irq, dev_id, regs);
+}
+
+static void ioasic_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned int count;
+
+	/*
+	 * The free-running counter is 32 bit which is good for about
+	 * 2 minutes, 50 seconds at possible count rates of upto 25MHz.
+	 */
+	count = ioasic_read(FCTR);
+	timerhi += (count < timerlo);	/* Wrap around */
+	timerlo = count;
 
-	if (!jiffies) {
+	if (jiffies == ~0) {
 		/*
-		 * If jiffies has overflowed in this timer_interrupt we must
+		 * If jiffies is to overflow in this timer_interrupt we must
 		 * update the timer[hi]/[lo] to make do_fast_gettimeoffset()
 		 * quotient calc still valid. -arca
 		 */
+		ioasic_write(FCTR, 0);
 		timerhi = timerlo = 0;
 	}
+
+	timer_interrupt(irq, dev_id, regs);
 }
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -473,6 +544,10 @@
 		write_32bit_cp0_register(CP0_COUNT, 0);
 		do_gettimeoffset = do_fast_gettimeoffset;
 		irq0.handler = r4k_timer_interrupt;
-	}
+	} else if (IOASIC) {
+		ioasic_write(FCTR, 0);
+		do_gettimeoffset = do_ioasic_gettimeoffset;
+		irq0.handler = ioasic_timer_interrupt;
+        }
 	board_time_init(&irq0);
 }
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/addrspace.h linux-mips-2.4.0-test5-20000731/include/asm-mips/addrspace.h
--- linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/addrspace.h	Tue Mar 28 04:27:19 2000
+++ linux-mips-2.4.0-test5-20000731/include/asm-mips/addrspace.h	Sat Aug  5 18:04:53 2000
@@ -4,6 +4,7 @@
  * for more details.
  *
  * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 2000 by Maciej W. Rozycki
  *
  * Defitions for the address spaces of the MIPS CPUs.
  */
@@ -22,20 +23,35 @@
 /*
  * Returns the kernel segment base of a given address
  */
+#ifndef __ASSEMBLY__
 #define KSEGX(a)                (((unsigned long)(a)) & 0xe0000000)
+#else
+#define KSEGX(a)                ((a) & 0xe0000000)
+#endif
 
 /*
  * Returns the physical address of a KSEG0/KSEG1 address
  */
+#ifndef __ASSEMBLY__
 #define PHYSADDR(a)		(((unsigned long)(a)) & 0x1fffffff)
+#else
+#define PHYSADDR(a)		((a) & 0x1fffffff)
+#endif
 
 /*
  * Map an address to a certain kernel segment
  */
+#ifndef __ASSEMBLY__
 #define KSEG0ADDR(a)		((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG0))
 #define KSEG1ADDR(a)		((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG1))
 #define KSEG2ADDR(a)		((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG2))
 #define KSEG3ADDR(a)		((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG3))
+#else
+#define KSEG0ADDR(a)		(((a) & 0x1fffffff) | KSEG0)
+#define KSEG1ADDR(a)		(((a) & 0x1fffffff) | KSEG1)
+#define KSEG2ADDR(a)		(((a) & 0x1fffffff) | KSEG2)
+#define KSEG3ADDR(a)		(((a) & 0x1fffffff) | KSEG3)
+#endif
 
 /*
  * Memory segments (64bit kernel mode addresses)
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/dec/interrupts.h linux-mips-2.4.0-test5-20000731/include/asm-mips/dec/interrupts.h
--- linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/dec/interrupts.h	Tue Mar 28 04:27:23 2000
+++ linux-mips-2.4.0-test5-20000731/include/asm-mips/dec/interrupts.h	Sat Aug  5 19:25:54 2000
@@ -36,7 +36,7 @@
 
 #define NR_INTS	11
 
-#ifndef _LANGUAGE_ASSEMBLY
+#ifndef __ASSEMBLY__
 /*
  * Data structure to hide the differences between the DECstation Interrupts
  *
@@ -50,6 +50,12 @@
 	unsigned int	iemask;		/* enabling interrupts in IRQ Controller	*/
 } decint_t;
 
+extern volatile unsigned int *isr;
+				/* address of the interrupt status register  */
+extern volatile unsigned int *imr;
+				/* address of the interrupt mask register    */
+extern decint_t dec_interrupt[NR_INTS];
+
 /*
  * Interrupt table structure to hide differences between different
  * systems such.
@@ -68,7 +74,7 @@
 extern void	dec_intr_rtc(void);
 
 extern void	kn02_io_int(void);
-extern void	kn02ba_io_int(void);
+extern void	kn02xa_io_int(void);
 extern void	kn03_io_int(void);
 
 extern void	intr_halt(void);
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/dec/ioasic.h linux-mips-2.4.0-test5-20000731/include/asm-mips/dec/ioasic.h
--- linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/dec/ioasic.h	Thu Jan  1 00:00:00 1970
+++ linux-mips-2.4.0-test5-20000731/include/asm-mips/dec/ioasic.h	Sat Aug  5 17:07:15 2000
@@ -0,0 +1,24 @@
+/*
+ *  linux/asm-mips/dec/ioasic.h
+ *
+ *  Copyright (C) 2000  Maciej W. Rozycki
+ *
+ *  DEC I/O ASIC access operations.
+ */
+
+#ifndef __ASM_DEC_IOASIC_H
+#define __ASM_DEC_IOASIC_H
+
+extern volatile unsigned int *ioasic_base;
+
+extern inline void ioasic_write(unsigned int reg, unsigned int v)
+{
+	ioasic_base[reg / 4] = v;
+}
+
+extern inline unsigned int ioasic_read(unsigned int reg)
+{
+	return ioasic_base[reg / 4];
+}
+
+#endif /* __ASM_DEC_IOASIC_H */
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/dec/ioasic_addrs.h linux-mips-2.4.0-test5-20000731/include/asm-mips/dec/ioasic_addrs.h
--- linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/dec/ioasic_addrs.h	Tue Mar 28 04:27:23 2000
+++ linux-mips-2.4.0-test5-20000731/include/asm-mips/dec/ioasic_addrs.h	Sat Aug  5 14:48:14 2000
@@ -17,25 +17,25 @@
 
 #define CHUNK_SIZE 0x00040000
 
-#define SYSTEM_ROM 	00*CHUNK_SIZE 		/* ??? */
-#define IOCTL 		01*CHUNK_SIZE 
-#define ESAR 		02*CHUNK_SIZE 
-#define LANCE 		03*CHUNK_SIZE 
-#define SCC0 		04*CHUNK_SIZE 
-#define VDAC_HI		05*CHUNK_SIZE		/* maxine only */
-#define SCC1 		06*CHUNK_SIZE 
-#define VDAC_LO		07*CHUNK_SIZE		/* maxine only */
-#define TOY 		08*CHUNK_SIZE 
-#define ISDN 		09*CHUNK_SIZE		/* maxine only */
-#define ERRADDR		09*CHUNK_SIZE 		/* 3maxplus only */
-#define CHKSYN 		10*CHUNK_SIZE 		/* 3maxplus only */
-#define ACCESS_BUS	10*CHUNK_SIZE 		/* maxine only */
-#define MCR 		11*CHUNK_SIZE 		/* 3maxplus only */
-#define FLOPPY 		11*CHUNK_SIZE 		/* maxine only */
-#define SCSI 		12*CHUNK_SIZE
-#define FLOPPY_DMA 	13*CHUNK_SIZE 		/* maxine only */
-#define SCSI_DMA 	14*CHUNK_SIZE 
-#define RESERVED_4 	15*CHUNK_SIZE 
+#define SYSTEM_ROM 	(00*CHUNK_SIZE)		/* ??? */
+#define IOCTL 		(01*CHUNK_SIZE)
+#define ESAR 		(02*CHUNK_SIZE)
+#define LANCE 		(03*CHUNK_SIZE)
+#define SCC0 		(04*CHUNK_SIZE)
+#define VDAC_HI		(05*CHUNK_SIZE)		/* maxine only */
+#define SCC1 		(06*CHUNK_SIZE)
+#define VDAC_LO		(07*CHUNK_SIZE)		/* maxine only */
+#define TOY 		(08*CHUNK_SIZE)
+#define ISDN 		(09*CHUNK_SIZE)		/* maxine only */
+#define ERRADDR		(09*CHUNK_SIZE)		/* 3maxplus only */
+#define CHKSYN 		(10*CHUNK_SIZE)		/* 3maxplus only */
+#define ACCESS_BUS	(10*CHUNK_SIZE)		/* maxine only */
+#define MCR 		(11*CHUNK_SIZE)		/* 3maxplus only */
+#define FLOPPY 		(11*CHUNK_SIZE)		/* maxine only */
+#define SCSI 		(12*CHUNK_SIZE)
+#define FLOPPY_DMA 	(13*CHUNK_SIZE)		/* maxine only */
+#define SCSI_DMA 	(14*CHUNK_SIZE)
+#define RESERVED_4 	(15*CHUNK_SIZE)
 
 /*
  * Offsets for IOCTL registers (relative to (system_base + IOCTL))
@@ -56,6 +56,7 @@
 #define SSR		0x100			/* System Support Register */
 #define SIR		0x110			/* System Interrupt Register */
 #define SIMR		0x120			/* System Interrupt Mask Register */
+#define FCTR		0x1e0			/* Free-Running Counter */
 
 /*
  * Handle partial word SCSI DMA transfers
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/dec/kn02xa.h linux-mips-2.4.0-test5-20000731/include/asm-mips/dec/kn02xa.h
--- linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/dec/kn02xa.h	Tue Mar 28 04:27:23 2000
+++ linux-mips-2.4.0-test5-20000731/include/asm-mips/dec/kn02xa.h	Sat Aug  5 15:35:24 2000
@@ -9,6 +9,7 @@
  *
  * Copyright (C) 1995,1996 by Paul M. Antoine, some code and definitions
  * are by curteousy of Chris Fraser.
+ * Copyright (C) 2000  Maciej W. Rozycki
  *
  * These are addresses which have to be known early in the boot process.
  * For other addresses refer to tc.h ioasic_addrs.h and friends.
@@ -19,16 +20,12 @@
 #include <asm/addrspace.h>
 
 /*
- * Motherboard regs (kseg1 addresses)
- */
-#define KN02XA_SSR_ADDR		KSEG1ADDR(0x1c040100)	/* system control & status reg */
-#define KN02XA_SIR_ADDR		KSEG1ADDR(0x1c040110)	/* system interrupt reg */
-#define KN02XA_SIRM_ADDR	KSEG1ADDR(0x1c040120)	/* system interrupt mask reg */
-
-/*
  * Some port addresses...
  * FIXME: these addresses are incomplete and need tidying up!
  */
-#define KN02XA_RTC_BASE	(KSEG1ADDR(0x1c000000 + 0x200000)) /* ASIC + SL8 */
+#define KN02XA_IOASIC_BASE	KSEG1ADDR(0x1c040000)	/* I/O ASIC */
+#define KN02XA_RTC_BASE		KSEG1ADDR(0x1e000000)	/* RTC */
+
+#define KN02XA_IOASIC_REG(r)	(KN02XA_IOASIC_BASE+(r))
 
 #endif /* __ASM_MIPS_DEC_KN02XA_H */
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/dec/kn03.h linux-mips-2.4.0-test5-20000731/include/asm-mips/dec/kn03.h
--- linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/dec/kn03.h	Tue Mar 28 04:27:23 2000
+++ linux-mips-2.4.0-test5-20000731/include/asm-mips/dec/kn03.h	Sat Aug  5 15:35:31 2000
@@ -8,6 +8,7 @@
  *
  * Copyright (C) 1995,1996 by Paul M. Antoine, some code and definitions
  * are by curteousy of Chris Fraser.
+ * Copyright (C) 2000  Maciej W. Rozycki
  *
  * These are addresses which have to be known early in the boot process.
  * For other addresses refer to tc.h ioasic_addrs.h and friends.
@@ -18,16 +19,12 @@
 #include <asm/addrspace.h>
 
 /*
- * Motherboard regs (kseg1 addresses)
- */
-#define KN03_SSR_ADDR	KSEG1ADDR(0x1f840100)	/* system control & status reg */
-#define KN03_SIR_ADDR	KSEG1ADDR(0x1f840110)	/* system interrupt reg */
-#define KN03_SIRM_ADDR	KSEG1ADDR(0x1f840120)	/* system interrupt mask reg */
-
-/*
  * Some port addresses...
  * FIXME: these addresses are incomplete and need tidying up!
  */
-#define KN03_RTC_BASE	(KSEG1ADDR(0x1f800000 + 0x200000)) /* ASIC + SL8 */
+#define KN03_IOASIC_BASE	KSEG1ADDR(0x1f840000)	/* I/O ASIC */
+#define KN03_RTC_BASE		KSEG1ADDR(0x1fa00000)	/* RTC */
+
+#define KN03_IOASIC_REG(r)	(KN03_IOASIC_BASE+(r))
 
 #endif /* __ASM_MIPS_DEC_KN03_H */
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/div64.h linux-mips-2.4.0-test5-20000731/include/asm-mips/div64.h
--- linux-mips-2.4.0-test5-20000731.macro/include/asm-mips/div64.h	Tue Mar 28 04:27:19 2000
+++ linux-mips-2.4.0-test5-20000731/include/asm-mips/div64.h	Sun Aug  6 05:22:36 2000
@@ -1,4 +1,7 @@
-/* $Id: div64.h,v 1.1 2000/01/28 23:18:43 ralf Exp $
+/*
+ * include/asm-mips/div64.h
+ * 
+ * Copyright (C) 2000  Maciej W. Rozycki
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -7,14 +10,104 @@
 #ifndef _ASM_DIV64_H
 #define _ASM_DIV64_H
 
+#include <asm/sgidefs.h>
+
 /*
- * Hey, we're already 64-bit, no
- * need to play games..
+ * No traps on overflows for any of these...
  */
-#define do_div(n,base) ({ \
-	int __res; \
-	__res = ((unsigned long) n) % (unsigned) base; \
-	n = ((unsigned long) n) / (unsigned) base; \
-	__res; })
+
+#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2)
+
+#define do_div64_32(res, high, low, base) ({ \
+	unsigned long __quot, __mod; \
+	unsigned long __cf, __tmp, __i; \
+	\
+	__asm__(".set	push\n\t" \
+		".set	noat\n\t" \
+		".set	noreorder\n\t" \
+		"b	1f\n\t" \
+		" li	%4,0x21\n" \
+		"0:\n\t" \
+		"sll	$1,%0,0x1\n\t" \
+		"srl	%3,%0,0x1f\n\t" \
+		"or	%0,$1,$2\n\t" \
+		"sll	%1,%1,0x1\n\t" \
+		"sll	%2,%2,0x1\n" \
+		"1:\n\t" \
+		"bnez	%3,2f\n\t" \
+		"sltu	$2,%0,%z5\n\t" \
+		"bnez	$2,3f\n\t" \
+		"2:\n\t" \
+		" addiu	%4,%4,-1\n\t" \
+		"subu	%0,%0,%z5\n\t" \
+		"addiu	%2,%2,1\n" \
+		"3:\n\t" \
+		"bnez	%4,0b\n\t" \
+		" srl	$2,%1,0x1f\n\t" \
+		".set	pop" \
+		: "=&r" (__mod), "=&r" (__tmp), "=&r" (__quot), "=&r" (__cf), \
+		  "=&r" (__i) \
+		: "Jr" (base), "0" (high), "1" (low), "2" (0), "3" (0) \
+		/* Aarrgh!  Ran out of gcc's limit on constraints... */ \
+		: "$1", "$2"); \
+	\
+	(res) = __quot; \
+	__mod; })
+
+#define do_div(n, base) ({ \
+	unsigned long long __quot; \
+	unsigned long __upper, __low, __high, __mod; \
+	\
+	__quot = (n); \
+	__high = __quot >> 32; \
+	__low = __quot; \
+	__upper = __high; \
+	\
+	if (__high) \
+		__asm__("divu	$0,%z2,%z3" \
+			: "=h" (__upper), "=l" (__high) \
+			: "Jr" (__high), "Jr" (base)); \
+	\
+	__mod = do_div64_32(__low, __upper, __low, base); \
+	\
+	__quot = __high; \
+	__quot = __quot << 32 | __low; \
+	(n) = __quot; \
+	__mod; })
+
+#else
+
+#define do_div64_32(res, high, low, base) ({ \
+	unsigned long __quot, __mod, __r0; \
+	\
+	__asm__("dsll32	%2,%z3,0\n\t" \
+		"or	%2,%2,%z4\n\t" \
+		"ddivu	$0,%2,%z5" \
+		: "=h" (__mod), "=l" (__quot), "=&r" (__r0) \
+		: "Jr" (high), "Jr" (low), "Jr" (base)); \
+	\
+	(res) = __quot; \
+	__mod; })
+
+#define do_div(n, base) ({ \
+	unsigned long long __quot; \
+	unsigned long __mod, __r0; \
+	\
+	__quot = (n); \
+	\
+	__asm__("dsll32	%2,%M3,0\n\t" \
+		"or	%2,%2,%L3\n\t" \
+		"ddivu	$0,%2,%z4\n\t" \
+		"mflo	%L1\n\t" \
+		"dsra32	%M1,%L1,0\n\t" \
+		"dsll32	%L1,%L1,0\n\t" \
+		"dsra32	%L1,%L1,0" \
+		: "=h" (__mod), "=r" (__quot), "=&r" (__r0) \
+		: "r" (n), "Jr" (base)); \
+	\
+	(n) = __quot; \
+	__mod; })
+
+#endif
 
 #endif /* _ASM_DIV64_H */