summaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/Makefile35
-rw-r--r--arch/mips/dec/Makefile4
-rw-r--r--arch/mips/dec/int-handler.S27
-rw-r--r--arch/mips/dec/irq.c4
-rw-r--r--arch/mips/dec/setup.c34
-rw-r--r--arch/mips/dec/time.c163
6 files changed, 178 insertions, 89 deletions
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 418f730ad..2e756ab25 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -35,7 +35,7 @@ endif
# 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,34 +47,43 @@ endif
# 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_RM7000
-CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
+GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap
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
@@ -172,12 +181,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
SUBDIRS := $(addprefix arch/mips/, tools) $(SUBDIRS) $(addprefix arch/mips/, kernel mm lib)
diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile
index d3f65947a..af3fc2c23 100644
--- a/arch/mips/dec/Makefile
+++ b/arch/mips/dec/Makefile
@@ -7,9 +7,9 @@
#
.S.s:
- $(CPP) $(CFLAGS) $< -o $*.s
+ $(CPP) $(AFLAGS) $< -o $@
.S.o:
- $(CC) $(CFLAGS) -c $< -o $*.o
+ $(CC) $(AFLAGS) -c $< -o $@
all: dec.o
O_TARGET := dec.o
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S
index db63068ca..9e76fc70f 100644
--- a/arch/mips/dec/int-handler.S
+++ b/arch/mips/dec/int-handler.S
@@ -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 @@ kn02_io_int: lui t0,0xbff0 # get interrupt status and mask
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 --git a/arch/mips/dec/irq.c b/arch/mips/dec/irq.c
index 91e1ce463..a15e2a45c 100644
--- a/arch/mips/dec/irq.c
+++ b/arch/mips/dec/irq.c
@@ -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];
-
unsigned long spurious_count = 0;
static inline void mask_irq(unsigned int irq_nr)
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
index 848d2bb74..9f6af4213 100644
--- a/arch/mips/dec/setup.c
+++ b/arch/mips/dec/setup.c
@@ -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_kn02ba(void);
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 @@ void __init dec_init_kn02(void)
* 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 @@ void __init dec_init_kn02ba(void)
/*
* 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 @@ void __init dec_init_kn02ca(void)
/*
* 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 @@ void __init dec_init_kn03(void)
/*
* 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 --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c
index 151ce507e..0f3998557 100644
--- a/arch/mips/dec/time.c
+++ b/arch/mips/dec/time.c
@@ -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 @@ extern rwlock_t xtime_lock;
/* 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 @@ static unsigned long do_fast_gettimeoffset(void)
{
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 @@ static unsigned long do_fast_gettimeoffset(void)
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 @@ static unsigned long do_fast_gettimeoffset(void)
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 @@ void do_gettimeofday(struct timeval *tv)
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 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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 @@ static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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 @@ void __init time_init(void)
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);
}