diff options
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/Makefile | 35 | ||||
-rw-r--r-- | arch/mips/dec/Makefile | 4 | ||||
-rw-r--r-- | arch/mips/dec/int-handler.S | 27 | ||||
-rw-r--r-- | arch/mips/dec/irq.c | 4 | ||||
-rw-r--r-- | arch/mips/dec/setup.c | 34 | ||||
-rw-r--r-- | arch/mips/dec/time.c | 163 |
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); } |