patch-2.1.44 linux/arch/mips/kernel/traps.c

Next file: linux/arch/mips/kernel/tyne-c.c
Previous file: linux/arch/mips/kernel/time.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.43/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c
@@ -1,5 +1,5 @@
 /*
- *  arch/mips/kernel/traps.c
+ * arch/mips/kernel/traps.c
  *
  * 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
@@ -13,26 +13,31 @@
  * but possibly by killing it outright if necessary).
  *
  * FIXME: This is the place for a fpu emulator.
+ *
+ * Modified for R3000 by Paul M. Antoine, 1995, 1996
  */
-#include <linux/head.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/timer.h>
+#include <linux/config.h>
+#include <linux/init.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
+#include <asm/branch.h>
+#include <asm/cachectl.h>
+#include <asm/jazz.h>
 #include <asm/vector.h>
-#include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/io.h>
-#include <asm/mipsregs.h>
 #include <asm/bootinfo.h>
+#include <asm/watch.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_SGI
+#include <asm/sgialib.h>
+#endif
+
+#undef CONF_DEBUG_EXCEPTIONS
 
 static inline void console_verbose(void)
 {
@@ -49,9 +54,12 @@
 extern asmlinkage void deskstation_tyne_handle_int(void);
 extern asmlinkage void mips_magnum_4000_handle_int(void);
 
-extern asmlinkage void handle_mod(void);
-extern asmlinkage void handle_tlbl(void);
-extern asmlinkage void handle_tlbs(void);
+extern asmlinkage void r4k_handle_mod(void);
+extern asmlinkage void r2300_handle_mod(void);
+extern asmlinkage void r4k_handle_tlbl(void);
+extern asmlinkage void r2300_handle_tlbl(void);
+extern asmlinkage void r4k_handle_tlbs(void);
+extern asmlinkage void r2300_handle_tlbs(void);
 extern asmlinkage void handle_adel(void);
 extern asmlinkage void handle_ades(void);
 extern asmlinkage void handle_ibe(void);
@@ -71,6 +79,10 @@
 static char *cpu_names[] = CPU_NAMES;
 
 unsigned long page_colour_mask;
+unsigned int watch_available = 0;
+
+void (*ibe_board_handler)(struct pt_regs *regs);
+void (*dbe_board_handler)(struct pt_regs *regs);
 
 int kstack_depth_to_print = 24;
 
@@ -80,48 +92,54 @@
  */
 #define MODULE_RANGE (8*1024*1024)
 
-void die_if_kernel(char * str, struct pt_regs * regs, long err)
+/*
+ * This routine abuses get_user()/put_user() to reference pointers
+ * with at least a bit of error checking ...
+ */
+void show_registers(char * str, struct pt_regs * regs, long err)
 {
 	int	i;
 	int	*stack;
 	u32	*sp, *pc, addr, module_start, module_end;
 	extern	char start_kernel, _etext;
 
-	if ((regs->cp0_status & (ST0_ERL|ST0_EXL)) == 0)
-		return;
-
-	sp = (u32 *)regs->reg29;
+	sp = (u32 *)regs->regs[29];
 	pc = (u32 *)regs->cp0_epc;
 
-	console_verbose();
-	printk("%s: %08lx\n", str, err );
-
 	show_regs(regs);
 
 	/*
 	 * Dump the stack
 	 */
-	if (STACK_MAGIC != *(u32 *)current->kernel_stack_page)
-		printk("Corrupted stack page\n");
 	printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
-		current->comm, current->pid, current->kernel_stack_page);
+		current->comm, current->pid, (unsigned long)current);
 	for(i=0;i<5;i++)
 		printk("%08x ", *sp++);
 	stack = (int *) sp;
+
 	for(i=0; i < kstack_depth_to_print; i++) {
+		unsigned int stackdata;
+
 		if (((u32) stack & (PAGE_SIZE -1)) == 0)
 			break;
 		if (i && ((i % 8) == 0))
 			printk("\n       ");
-		printk("%08lx ", get_user(stack++));
+		if (get_user(stackdata, stack++) < 0) {
+			printk("(Bad stack address)");
+			break;
+		}
+		printk("%08x ", stackdata);
 	}
 	printk("\nCall Trace: ");
 	stack = (int *)sp;
 	i = 1;
 	module_start = VMALLOC_START;
 	module_end = module_start + MODULE_RANGE;
-	while (((u32)stack & (PAGE_SIZE -1)) != 0) {
-		addr = get_user(stack++);
+	while (((unsigned long)stack & (PAGE_SIZE -1)) != 0) {
+		if (get_user(addr, stack++) < 0) {
+			printk("(Bad address)\n");
+			break;
+		}
 		/*
 		 * If the address is either in the text segment of the
 		 * kernel, or in the region which contains vmalloc'ed
@@ -141,9 +159,7 @@
 	}
 
 	printk("\nCode : ");
-	if ((!verify_area(VERIFY_READ, pc, 5 * sizeof(*pc)) ||
-	     KSEGX(pc) == KSEG0 ||
-	     KSEGX(pc) == KSEG1) &&
+	if ((KSEGX(pc) == KSEG0 || KSEGX(pc) == KSEG1) &&
 	    (((unsigned long) pc & 3) == 0))
 	{
 		for(i=0;i<5;i++)
@@ -152,230 +168,353 @@
 	}
 	else
 		printk("(Bad address in epc)\n");
-while(1);
 	do_exit(SIGSEGV);
 }
 
-static void
-fix_ade(struct pt_regs *regs, int write)
-{
-	printk("Received address error (ade%c)\n", write ? 's' : 'l');
-	panic("Fixing address errors not implemented yet");
-}
-
-void do_adel(struct pt_regs *regs)
+void die_if_kernel(const char * str, struct pt_regs * regs, long err)
 {
-	if(current->tss.mflags & MF_FIXADE)
-	{
-		fix_ade(regs, 0);
+	/*
+	 * Just return if in user mode.
+	 * XXX
+	 */
+#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2)
+	if (!((regs)->cp0_status & 0x4))
 		return;
-	}
+#endif
+#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4)
+	if (!(regs->cp0_status & 0x18))
+		return;
+#endif
+	console_verbose();
+	printk("%s: %04lx\n", str, err & 0xffff);
 	show_regs(regs);
-while(1);
-	dump_tlb_nonwired();
-	send_sig(SIGSEGV, current, 1);
+	do_exit(SIGSEGV);
 }
 
-void do_ades(struct pt_regs *regs)
+static void default_be_board_handler(struct pt_regs *regs)
 {
-	struct task_struct *p;
-	unsigned long	pc = regs->cp0_epc;
-	int	i;
-
-	if(current->tss.mflags & MF_FIXADE)
-	{
-		fix_ade(regs, 1);
-		return;
-	}
-while(1);
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if(p->pid >= 2) {
-			printk("Process %d\n", p->pid);
-			dump_list_process(p, pc);
-		}
-	}
-	read_unlock(&tasklist_lock);
-	show_regs(regs);
-	dump_tlb_nonwired();
-	send_sig(SIGSEGV, current, 1);
+	/*
+	 * Assume it would be too dangerous to continue ...
+	 */
+	force_sig(SIGBUS, current);
 }
 
-/*
- * The ibe/dbe exceptions are signaled by onboard hardware and should get
- * a board specific handlers to get maximum available information. Bus
- * errors are always symptom of hardware malfunction or a kernel error.
- *
- * FIXME: Linux/68k sends a SIGSEGV for a buserror which seems to be wrong.
- * This is certainly wrong. Actually, all hardware errors (ades,adel,ibe,dbe)
- * are bus errors and therefor should send a SIGBUS! (Andy)
- */
 void do_ibe(struct pt_regs *regs)
 {
-show_regs(regs);
-while(1);
-	send_sig(SIGBUS, current, 1);
+	lock_kernel();
+	ibe_board_handler(regs);
+	unlock_kernel();
 }
 
 void do_dbe(struct pt_regs *regs)
 {
-show_regs(regs);
-while(1);
-	send_sig(SIGBUS, current, 1);
+	lock_kernel();
+	dbe_board_handler(regs);
+	unlock_kernel();
 }
 
 void do_ov(struct pt_regs *regs)
 {
-show_regs(regs);
-while(1);
-	send_sig(SIGFPE, current, 1);
+	lock_kernel();
+#ifdef CONF_DEBUG_EXCEPTIONS
+	show_regs(regs);
+#endif
+	if (compute_return_epc(regs))
+		goto out;
+	force_sig(SIGFPE, current);
+out:
+	unlock_kernel();
 }
 
-void do_fpe(struct pt_regs *regs)
+void do_fpe(struct pt_regs *regs, unsigned int fcr31)
 {
-show_regs(regs);
-while(1);
-	send_sig(SIGFPE, current, 1);
+	lock_kernel();
+#ifdef CONF_DEBUG_EXCEPTIONS
+	show_regs(regs);
+#endif
+	printk("Caught floating exception at epc == %08lx, fcr31 == %08x\n",
+	       regs->cp0_epc, fcr31);
+	if (compute_return_epc(regs))
+		goto out;
+	force_sig(SIGFPE, current);
+out:
+	unlock_kernel();
+}
+
+static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode)
+{
+	unsigned int *epc;
+
+	epc = (unsigned int *) (unsigned long) regs->cp0_epc;
+	if (regs->cp0_cause & CAUSEF_BD)
+		epc += 4;
+
+	if (verify_area(VERIFY_READ, epc, 4)) {
+		force_sig(SIGSEGV, current);
+		return 1;
+	}
+	*opcode = *epc;
+
+	return 0;
+}
+
+static inline void
+do_bp_and_tr(struct pt_regs *regs, char *exc, unsigned int trapcode)
+{
+	/*
+	 * (A short test says that IRIX 5.3 sends SIGTRAP for all break
+	 * insns, even for break codes that indicate arithmetic failures.
+	 * Wiered ...)
+	 */
+	force_sig(SIGTRAP, current);
+#ifdef CONF_DEBUG_EXCEPTIONS
+	show_regs(regs);
+#endif
 }
 
 void do_bp(struct pt_regs *regs)
 {
-show_regs(regs);
-while(1);
-	send_sig(SIGILL, current, 1);
+	unsigned int opcode, bcode;
+
+	lock_kernel();
+	/*
+	 * There is the ancient bug in the MIPS assemblers that the break
+	 * code starts left to bit 16 instead to bit 6 in the opcode.
+	 * Gas is bug-compatible ...
+	 */
+#ifdef CONF_DEBUG_EXCEPTIONS
+	printk("BREAKPOINT at %08lx\n", regs->cp0_epc);
+#endif
+	if (get_insn_opcode(regs, &opcode))
+		goto out;
+	bcode = ((opcode >> 16) & ((1 << 20) - 1));
+
+	do_bp_and_tr(regs, "bp", bcode);
+
+	if (compute_return_epc(regs))
+		goto out;
+out:
+	unlock_kernel();
 }
 
 void do_tr(struct pt_regs *regs)
 {
-show_regs(regs);
-while(1);
-	send_sig(SIGILL, current, 1);
+	unsigned int opcode, bcode;
+
+	lock_kernel();
+	if (get_insn_opcode(regs, &opcode))
+		goto out;
+	bcode = ((opcode >> 6) & ((1 << 20) - 1));
+
+	do_bp_and_tr(regs, "tr", bcode);
+out:
+	unlock_kernel();
 }
 
 void do_ri(struct pt_regs *regs)
 {
-	struct task_struct *p;
-	int	i;
-
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if(p->pid >= 2) {
-			printk("Process %d\n", p->pid);
-			dump_list_process(p, 0x7ffff000);
-		}
-	}
+	lock_kernel();
+#ifdef CONF_DEBUG_EXCEPTIONS
 	show_regs(regs);
-while(1);
-	send_sig(SIGILL, current, 1);
+#endif
+	printk("[%s:%d] Illegal instruction at %08lx ra=%08lx\n",
+	       current->comm, current->pid, regs->cp0_epc, regs->regs[31]);
+	if (compute_return_epc(regs))
+		goto out;
+	force_sig(SIGILL, current);
+out:
+	unlock_kernel();
 }
 
 void do_cpu(struct pt_regs *regs)
 {
 	unsigned int cpid;
 
+	lock_kernel();
 	cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
-	switch(cpid)
+	if (cpid == 1)
 	{
-	case 1:
 		regs->cp0_status |= ST0_CU1;
-		break;
-	case 0:
-		/*
-		 * CPU for cp0 can only happen in user mode
-		 */
-	case 2:
-	case 3:
-		send_sig(SIGILL, current, 1);
-		break;
+		goto out;
 	}
+	force_sig(SIGILL, current);
+out:
+	unlock_kernel();
 }
 
 void do_vcei(struct pt_regs *regs)
 {
+	lock_kernel();
 	/*
-	 * Only possible on R4[04]00[SM]C. No handler because
-	 * I don't have such a cpu.
+	 * Only possible on R4[04]00[SM]C. No handler because I don't have
+	 * such a cpu.  Theory says this exception doesn't happen.
 	 */
-	panic("Caught VCEI exception - can't handle yet\n");
+	panic("Caught VCEI exception - should not happen");
+	unlock_kernel();
 }
 
 void do_vced(struct pt_regs *regs)
 {
+	lock_kernel();
 	/*
-	 * Only possible on R4[04]00[SM]C. No handler because
-	 * I don't have such a cpu.
+	 * Only possible on R4[04]00[SM]C. No handler because I don't have
+	 * such a cpu.  Theory says this exception doesn't happen.
 	 */
-	panic("Caught VCED exception - can't handle yet\n");
+	panic("Caught VCE exception - should not happen");
+	unlock_kernel();
 }
 
 void do_watch(struct pt_regs *regs)
 {
-	panic("Caught WATCH exception - can't handle yet\n");
+	lock_kernel();
+	/*
+	 * We use the watch exception where available to detect stack
+	 * overflows.
+	 */
+	show_regs(regs);
+	panic("Caught WATCH exception - probably caused by stack overflow.");
+	unlock_kernel();
 }
 
 void do_reserved(struct pt_regs *regs)
 {
+	lock_kernel();
 	/*
 	 * Game over - no way to handle this if it ever occurs.
 	 * Most probably caused by a new unknown cpu type or
 	 * after another deadly hard/software error.
 	 */
-	panic("Caught reserved exception - can't handle.\n");
+	panic("Caught reserved exception - should not happen.");
+	unlock_kernel();
 }
 
-void trap_init(void)
+static inline void watch_init(unsigned long cputype)
 {
-	unsigned long	i;
-	void watch_set(unsigned long, unsigned long);
+	switch(cputype) {
+	case CPU_R10000:
+	case CPU_R4000MC:
+	case CPU_R4400MC:
+	case CPU_R4000SC:
+	case CPU_R4400SC:
+	case CPU_R4000PC:
+	case CPU_R4400PC:
+	case CPU_R4200:
+	case CPU_R4300:
+		set_except_vector(23, handle_watch);
+		watch_available = 1;
+		break;
+	}
+}
 
-	if(boot_info.machtype == MACH_MIPS_MAGNUM_4000)
+typedef asmlinkage int (*syscall_t)(void *a0,...);
+asmlinkage int (*do_syscalls)(struct pt_regs *regs, syscall_t fun, int narg);
+extern asmlinkage int r4k_do_syscalls(struct pt_regs *regs,
+				      syscall_t fun, int narg);
+extern asmlinkage int r2300_do_syscalls(struct pt_regs *regs,
+					syscall_t fun, int narg);
+
+asmlinkage void (*save_fp_context)(struct sigcontext *sc);
+extern asmlinkage void r4k_save_fp_context(struct sigcontext *sc);
+extern asmlinkage void r2300_save_fp_context(struct sigcontext *sc);
+extern asmlinkage void r6000_save_fp_context(struct sigcontext *sc);
+
+asmlinkage void (*restore_fp_context)(struct sigcontext *sc);
+extern asmlinkage void r4k_restore_fp_context(struct sigcontext *sc);
+extern asmlinkage void r2300_restore_fp_context(struct sigcontext *sc);
+extern asmlinkage void r6000_restore_fp_context(struct sigcontext *sc);
+
+extern asmlinkage void r4xx0_resume(void *tsk);
+extern asmlinkage void r2300_resume(void *tsk);
+
+__initfunc(void trap_init(void))
+{
+	extern char except_vec0_r4000, except_vec0_r4600, except_vec0_r2300;
+	extern char except_vec1_generic, except_vec2_generic;
+	extern char except_vec3_generic, except_vec3_r4000;
+	unsigned long i;
+
+	if(mips_machtype == MACH_MIPS_MAGNUM_4000 ||
+	   mips_machtype == MACH_DESKSTATION_RPC44 ||
+	   mips_machtype == MACH_SNI_RM200_PCI)
 		EISA_bus = 1;
 
+	/* Copy the generic exception handler code to it's final destination. */
+	memcpy((void *)(KSEG0 + 0x80), &except_vec1_generic, 0x80);
+	memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80);
+	memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, 0x80);
+
 	/*
 	 * Setup default vectors
 	 */
-	for (i=0;i<=31;i++)
+	for(i = 0; i <= 31; i++)
 		set_except_vector(i, handle_reserved);
 
 	/*
-	 * Handling the following exceptions depends mostly of the cpu type
+	 * Only some CPUs have the watch exception.
 	 */
-	switch(boot_info.cputype) {
+	watch_init(mips_cputype);
+
 	/*
-	 * The R10000 is in most aspects similar to the R4400.  It however
-	 * should get some special optimizations.
+	 * Handling the following exceptions depends mostly of the cpu type
 	 */
+	switch(mips_cputype) {
 	case CPU_R10000:
+		/*
+		 * The R10000 is in most aspects similar to the R4400.  It
+		 * should get some special optimizations.
+		 */
 		write_32bit_cp0_register(CP0_FRAMEMASK, 0);
 		set_cp0_status(ST0_XX, ST0_XX);
+		/*
+		 * Actually this mask stands for only 16k cache.  This is
+		 * correct since the R10000 has multiple ways in it's cache.
+		 */
 		page_colour_mask = 0x3000;
+		/*
+		 * The R10k might even work for Linux/MIPS - but we're paranoid
+		 * and refuse to run until this is tested on real silicon
+		 */
 		panic("CPU too expensive - making holiday in the ANDES!");
 		break;
 	case CPU_R4000MC:
 	case CPU_R4400MC:
 	case CPU_R4000SC:
 	case CPU_R4400SC:
-		/*
-		 * Handlers not implemented yet.  If should ever be used -
-		 * otherwise it's a bug in the Linux/MIPS kernel, anyway.
+		/* XXX The following won't work because we _cannot_
+		 * XXX perform any load/store before the VCE handler.
 		 */
 		set_except_vector(14, handle_vcei);
 		set_except_vector(31, handle_vced);
 	case CPU_R4000PC:
 	case CPU_R4400PC:
 	case CPU_R4200:
-     /* case CPU_R4300: */
+	case CPU_R4300:
+     /* case CPU_R4640: */
+	case CPU_R4600:
+        case CPU_R5000:
+		if(mips_cputype != CPU_R4600)
+			memcpy((void *)KSEG0, &except_vec0_r4000, 0x80);
+		else
+			memcpy((void *)KSEG0, &except_vec0_r4600, 0x80);
+
 		/*
-		 * Use watch exception to trap on access to address zero
+		 * The idea is that this special r4000 general exception
+		 * vector will check for VCE exceptions before calling
+		 * out of the exception array.  XXX TODO
 		 */
-		set_except_vector(23, handle_watch);
-		watch_set(KSEG0, 3);
-	case CPU_R4600:
-		set_except_vector(1, handle_mod);
-		set_except_vector(2, handle_tlbl);
-		set_except_vector(3, handle_tlbs);
+		memcpy((void *)(KSEG0 + 0x100), (void *) KSEG0, 0x80);
+		memcpy((void *)(KSEG0 + 0x180), &except_vec3_r4000, 0x80);
+
+		do_syscalls = r4k_do_syscalls;
+		save_fp_context = r4k_save_fp_context;
+		restore_fp_context = r4k_restore_fp_context;
+		resume = r4xx0_resume;
+		set_except_vector(1, r4k_handle_mod);
+		set_except_vector(2, r4k_handle_tlbl);
+		set_except_vector(3, r4k_handle_tlbs);
 		set_except_vector(4, handle_adel);
 		set_except_vector(5, handle_ades);
+
 		/*
 		 * The following two are signaled by onboard hardware and
 		 * should get board specific handlers to get maximum
@@ -394,36 +533,89 @@
 
 		/*
 		 * Compute mask for page_colour().  This is based on the
-		 * size of the data cache.  Does the size of the icache
-		 * need to be accounted for?
+		 * size of the data cache.
 		 */
 		i = read_32bit_cp0_register(CP0_CONFIG);
 		i = (i >> 26) & 7;
 		page_colour_mask = 1 << (12 + i);
 		break;
+	case CPU_R6000:
+	case CPU_R6000A:
+		save_fp_context = r6000_save_fp_context;
+		restore_fp_context = r6000_restore_fp_context;
+#if 0
+		/*
+		 * The R6000 is the only R-series CPU that features a machine
+		 * check exception (similar to the R4000 cache error) and
+		 * unaligned ldc1/sdc1 exception.  The handlers have not been
+		 * written yet.  Well, anyway there is no R6000 machine on the
+		 * current list of targets for Linux/MIPS.
+		 */
+		set_except_vector(14, handle_mc);
+		set_except_vector(15, handle_ndc);
+#endif
 	case CPU_R2000:
 	case CPU_R3000:
 	case CPU_R3000A:
+		/*
+		 * Actually don't know about these, but let's guess - PMA
+		 */
+		memcpy((void *)KSEG0, &except_vec0_r2300, 0x80);
+		do_syscalls = r2300_do_syscalls;
+		save_fp_context = r2300_save_fp_context;
+		restore_fp_context = r2300_restore_fp_context;
+		resume = r2300_resume;
+		set_except_vector(1, r2300_handle_mod);
+		set_except_vector(2, r2300_handle_tlbl);
+		set_except_vector(3, r2300_handle_tlbs);
+		set_except_vector(4, handle_adel);
+		set_except_vector(5, handle_ades);
+		/*
+		 * The Data Bus Error/ Instruction Bus Errors are signaled
+		 * by external hardware.  Therefore these two expection have
+		 * board specific handlers.
+		 */
+		set_except_vector(6, handle_ibe);
+		set_except_vector(7, handle_dbe);
+		ibe_board_handler = default_be_board_handler;
+		dbe_board_handler = default_be_board_handler;
+
+		set_except_vector(8, handle_sys);
+		set_except_vector(9, handle_bp);
+		set_except_vector(10, handle_ri);
+		set_except_vector(11, handle_cpu);
+		set_except_vector(12, handle_ov);
+		set_except_vector(13, handle_tr);
+		set_except_vector(15, handle_fpe);
+
+		/*
+		 * Compute mask for page_colour().  This is based on the
+		 * size of the data cache.  Does the size of the icache
+		 * need to be accounted for?
+		 *
+		 * FIXME: is any of this necessary for the R3000, which
+		 *        doesn't have a config register?
+		 *        (No, the R2000, R3000 family has a physical indexed
+		 *        cache and doesn't need this braindamage.)
+		i = read_32bit_cp0_register(CP0_CONFIG);
+		i = (i >> 26) & 7;
+		page_colour_mask = 1 << (12 + i);
+		 */
+		break;
 	case CPU_R3041:
 	case CPU_R3051:
 	case CPU_R3052:
 	case CPU_R3081:
 	case CPU_R3081E:
-	case CPU_R6000:
-	case CPU_R6000A:
 	case CPU_R8000:
 		printk("Detected unsupported CPU type %s.\n",
-			cpu_names[boot_info.cputype]);
-		panic("Can't handle CPU\n");
+			cpu_names[mips_cputype]);
+		panic("Can't handle CPU");
 		break;
 
 	case CPU_UNKNOWN:
 	default:
 		panic("Unknown CPU type");
 	}
-
-	/*
-	 * The interrupt handler mostly depends of the board type.
-	 */
-	set_except_vector(0, feature->handle_int);
+	flush_cache_all();
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov