From 14f18b7f7e58de9a34c4b5fd38d5f73f22fba7ac Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 1 Mar 2005 18:15:08 +0000 Subject: On 24K we did always disable cache parity protection - obviously not the greatest thing to do. Try to enable parity protection, check if we actually succeeded and print a message about the outcome of this. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index a53b1ed7b38..d06db5f8115 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -736,16 +736,12 @@ static inline void parity_protection_init(void) { switch (current_cpu_data.cputype) { case CPU_24K: - /* 24K cache parity not currently implemented in FPGA */ - printk(KERN_INFO "Disable cache parity protection for " - "MIPS 24K CPU.\n"); - write_c0_ecc(read_c0_ecc() & ~0x80000000); - break; case CPU_5KC: - /* Set the PE bit (bit 31) in the c0_ecc register. */ - printk(KERN_INFO "Enable cache parity protection for " - "MIPS 5KC/24K CPUs.\n"); - write_c0_ecc(read_c0_ecc() | 0x80000000); + write_c0_ecc(0x80000000); + back_to_back_c0_hazard(); + /* Set the PE bit (bit 31) in the c0_errctl register. */ + printk(KERN_INFO "Cache parity protection %sabled\n", + (read_c0_ecc() & 0x80000000) ? "en" : "dis"); break; case CPU_20KC: case CPU_25KF: -- cgit v1.2.3 From fe00f943e0ef98b4057abcc2940d631a975b43cd Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 1 Mar 2005 19:22:29 +0000 Subject: Sparseify MIPS. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index d06db5f8115..f9a6a566555 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -339,9 +339,9 @@ asmlinkage void do_be(struct pt_regs *regs) static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) { - unsigned int *epc; + unsigned int __user *epc; - epc = (unsigned int *) regs->cp0_epc + + epc = (unsigned int __user *) regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) != 0); if (!get_user(*opcode, epc)) return 0; @@ -371,7 +371,7 @@ static struct task_struct *ll_task = NULL; static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode) { - unsigned long value, *vaddr; + unsigned long value, __user *vaddr; long offset; int signal = 0; @@ -385,7 +385,8 @@ static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode) offset <<= 16; offset >>= 16; - vaddr = (unsigned long *)((long)(regs->regs[(opcode & BASE) >> 21]) + offset); + vaddr = (unsigned long __user *) + ((unsigned long)(regs->regs[(opcode & BASE) >> 21]) + offset); if ((unsigned long)vaddr & 3) { signal = SIGBUS; @@ -418,7 +419,8 @@ sig: static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode) { - unsigned long *vaddr, reg; + unsigned long __user *vaddr; + unsigned long reg; long offset; int signal = 0; @@ -432,7 +434,8 @@ static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode) offset <<= 16; offset >>= 16; - vaddr = (unsigned long *)((long)(regs->regs[(opcode & BASE) >> 21]) + offset); + vaddr = (unsigned long __user *) + ((unsigned long)(regs->regs[(opcode & BASE) >> 21]) + offset); reg = (opcode & RT) >> 16; if ((unsigned long)vaddr & 3) { @@ -498,7 +501,7 @@ asmlinkage void do_ov(struct pt_regs *regs) info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)regs->cp0_epc; + info.si_addr = (void __user *) regs->cp0_epc; force_sig_info(SIGFPE, &info, current); } @@ -584,7 +587,7 @@ asmlinkage void do_bp(struct pt_regs *regs) info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)regs->cp0_epc; + info.si_addr = (void __user *) regs->cp0_epc; force_sig_info(SIGFPE, &info, current); break; default: @@ -621,7 +624,7 @@ asmlinkage void do_tr(struct pt_regs *regs) info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)regs->cp0_epc; + info.si_addr = (void __user *) regs->cp0_epc; force_sig_info(SIGFPE, &info, current); break; default: -- cgit v1.2.3 From 6dd04688520d7abe4883b2a79fa720291d76b140 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 12 Apr 2005 11:04:15 +0000 Subject: When simulating ll/sc compute the return EPC before modifying the registers. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index f9a6a566555..77f796b9975 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -408,9 +408,10 @@ static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode) preempt_enable(); + compute_return_epc(regs); + regs->regs[(opcode & RT) >> 16] = value; - compute_return_epc(regs); return; sig: @@ -459,9 +460,9 @@ static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode) goto sig; } + compute_return_epc(regs); regs->regs[reg] = 1; - compute_return_epc(regs); return; sig: -- cgit v1.2.3 From 05b8042ac6d35383c2fcc171ed932426c4e09ed1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 12 Apr 2005 20:26:05 +0000 Subject: Fix one more case of computing the return EPC after the registers have already been modified. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 77f796b9975..94d9141c04c 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -447,9 +447,9 @@ static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode) preempt_disable(); if (ll_bit == 0 || ll_task != current) { + compute_return_epc(regs); regs->regs[reg] = 0; preempt_enable(); - compute_return_epc(regs); return; } -- cgit v1.2.3 From 3c37026d43c47bec4710cbda286f4a17f416f5e6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Apr 2005 17:43:59 +0000 Subject: NPTL, round one. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 94d9141c04c..15fed020215 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -360,6 +360,10 @@ static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) #define OFFSET 0x0000ffff #define LL 0xc0000000 #define SC 0xe0000000 +#define SPEC3 0x7c000000 +#define RD 0x0000f800 +#define FUNC 0x0000003f +#define RDHWR 0x0000003b /* * The ll_bit is cleared by r*_switch.S @@ -495,6 +499,37 @@ static inline int simulate_llsc(struct pt_regs *regs) return -EFAULT; /* Strange things going on ... */ } +/* + * Simulate trapping 'rdhwr' instructions to provide user accessible + * registers not implemented in hardware. The only current use of this + * is the thread area pointer. + */ +static inline int simulate_rdhwr(struct pt_regs *regs) +{ + struct thread_info *ti = current->thread_info; + unsigned int opcode; + + if (unlikely(get_insn_opcode(regs, &opcode))) + return -EFAULT; + + if (unlikely(compute_return_epc(regs))) + return -EFAULT; + + if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) { + int rd = (opcode & RD) >> 11; + int rt = (opcode & RT) >> 16; + switch (rd) { + case 29: + regs->regs[rt] = ti->tp_value; + break; + default: + return -EFAULT; + } + } + + return 0; +} + asmlinkage void do_ov(struct pt_regs *regs) { siginfo_t info; @@ -641,6 +676,9 @@ asmlinkage void do_ri(struct pt_regs *regs) if (!simulate_llsc(regs)) return; + if (!simulate_rdhwr(regs)) + return; + force_sig(SIGILL, current); } @@ -654,11 +692,13 @@ asmlinkage void do_cpu(struct pt_regs *regs) switch (cpid) { case 0: - if (cpu_has_llsc) - break; + if (!cpu_has_llsc) + if (!simulate_llsc(regs)) + return; - if (!simulate_llsc(regs)) + if (!simulate_rdhwr(regs)) return; + break; case 1: -- cgit v1.2.3 From cd21dfcfbb5c43de54f6be795dde07397da2bc2f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 28 Apr 2005 13:39:10 +0000 Subject: Fix preemption and SMP problems in the FP emulator code. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 15fed020215..b3ecd02757c 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -551,6 +551,14 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) preempt_disable(); +#ifdef CONFIG_PREEMPT + if (!is_fpu_owner()) { + /* We might lose fpu before disabling preempt... */ + own_fpu(); + BUG_ON(!used_math()); + restore_fp(current); + } +#endif /* * Unimplemented operation exception. If we've got the full * software emulator on-board, let's use it... @@ -562,11 +570,18 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) * a bit extreme for what should be an infrequent event. */ save_fp(current); + /* Ensure 'resume' not overwrite saved fp context again. */ + lose_fpu(); + + preempt_enable(); /* Run the emulator */ sig = fpu_emulator_cop1Handler (0, regs, ¤t->thread.fpu.soft); + preempt_disable(); + + own_fpu(); /* Using the FPU again. */ /* * We can't allow the emulated instruction to leave any of * the cause bit set in $fcr31. @@ -712,6 +727,8 @@ asmlinkage void do_cpu(struct pt_regs *regs) set_used_math(); } + preempt_enable(); + if (!cpu_has_fpu) { int sig = fpu_emulator_cop1Handler(0, regs, ¤t->thread.fpu.soft); @@ -719,8 +736,6 @@ asmlinkage void do_cpu(struct pt_regs *regs) force_sig(sig, current); } - preempt_enable(); - return; case 2: -- cgit v1.2.3 From e50c0a8fa60da9ac0e0a70caa8a3a803815c1f2f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 31 May 2005 11:49:19 +0000 Subject: Support the MIPS32 / MIPS64 DSP ASE. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 49 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index b3ecd02757c..9419a3542c2 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ extern asmlinkage void handle_tr(void); extern asmlinkage void handle_fpe(void); extern asmlinkage void handle_mdmx(void); extern asmlinkage void handle_watch(void); +extern asmlinkage void handle_dsp(void); extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); @@ -775,6 +777,14 @@ asmlinkage void do_mcheck(struct pt_regs *regs) (regs->cp0_status & ST0_TS) ? "" : "not "); } +asmlinkage void do_dsp(struct pt_regs *regs) +{ + if (cpu_has_dsp) + panic("Unexpected DSP exception\n"); + + force_sig(SIGILL, current); +} + asmlinkage void do_reserved(struct pt_regs *regs) { /* @@ -984,9 +994,12 @@ void __init per_cpu_trap_init(void) #endif if (current_cpu_data.isa_level == MIPS_CPU_ISA_IV) status_set |= ST0_XX; - change_c0_status(ST0_CU|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, + change_c0_status(ST0_CU|ST0_MX|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, status_set); + if (cpu_has_dsp) + set_c0_status(ST0_MX); + /* * Some MIPS CPUs have a dedicated interrupt vector which reduces the * interrupt processing overhead. Use it where available. @@ -1078,21 +1091,6 @@ void __init trap_init(void) set_except_vector(11, handle_cpu); set_except_vector(12, handle_ov); set_except_vector(13, handle_tr); - set_except_vector(22, handle_mdmx); - - if (cpu_has_fpu && !cpu_has_nofpuex) - set_except_vector(15, handle_fpe); - - if (cpu_has_mcheck) - set_except_vector(24, handle_mcheck); - - if (cpu_has_vce) - /* Special exception: R4[04]00 uses also the divec space. */ - memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x100); - else if (cpu_has_4kex) - memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80); - else - memcpy((void *)(CAC_BASE + 0x080), &except_vec3_generic, 0x80); if (current_cpu_data.cputype == CPU_R6000 || current_cpu_data.cputype == CPU_R6000A) { @@ -1108,6 +1106,25 @@ void __init trap_init(void) //set_except_vector(15, handle_ndc); } + if (cpu_has_fpu && !cpu_has_nofpuex) + set_except_vector(15, handle_fpe); + + set_except_vector(22, handle_mdmx); + + if (cpu_has_mcheck) + set_except_vector(24, handle_mcheck); + + if (cpu_has_dsp) + set_except_vector(26, handle_dsp); + + if (cpu_has_vce) + /* Special exception: R4[04]00 uses also the divec space. */ + memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x100); + else if (cpu_has_4kex) + memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80); + else + memcpy((void *)(CAC_BASE + 0x080), &except_vec3_generic, 0x80); + signal_init(); #ifdef CONFIG_MIPS32_COMPAT signal32_init(); -- cgit v1.2.3 From 260c96738cf30f489108cd0fb3f10dcd11cbb5ca Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 16 Jun 2005 20:39:12 +0000 Subject: Mark __die() "noreturn" for real. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 9419a3542c2..b502dc970b3 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -254,8 +254,9 @@ void show_registers(struct pt_regs *regs) static DEFINE_SPINLOCK(die_lock); -NORET_TYPE void __die(const char * str, struct pt_regs * regs, - const char * file, const char * func, unsigned long line) +NORET_TYPE void ATTRIB_NORET __die(const char * str, struct pt_regs * regs, + const char * file, const char * func, + unsigned long line) { static int die_counter; -- cgit v1.2.3 From 3b2396d972ce030e942fef9fcbea1e411b1a62db Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 22 Jun 2005 20:43:29 +0000 Subject: Use correct names for bits in the R3k cp0.status register. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 67 +++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 26 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index b502dc970b3..46636a2fe98 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -9,7 +9,7 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000, 01 MIPS Technologies, Inc. - * Copyright (C) 2002, 2003, 2004 Maciej W. Rozycki + * Copyright (C) 2002, 2003, 2004, 2005 Maciej W. Rozycki */ #include #include @@ -203,32 +203,47 @@ void show_regs(struct pt_regs *regs) printk("Status: %08x ", (uint32_t) regs->cp0_status); - if (regs->cp0_status & ST0_KX) - printk("KX "); - if (regs->cp0_status & ST0_SX) - printk("SX "); - if (regs->cp0_status & ST0_UX) - printk("UX "); - switch (regs->cp0_status & ST0_KSU) { - case KSU_USER: - printk("USER "); - break; - case KSU_SUPERVISOR: - printk("SUPERVISOR "); - break; - case KSU_KERNEL: - printk("KERNEL "); - break; - default: - printk("BAD_MODE "); - break; + if (current_cpu_data.isa_level == MIPS_CPU_ISA_I) { + if (regs->cp0_status & ST0_KUO) + printk("KUo "); + if (regs->cp0_status & ST0_IEO) + printk("IEo "); + if (regs->cp0_status & ST0_KUP) + printk("KUp "); + if (regs->cp0_status & ST0_IEP) + printk("IEp "); + if (regs->cp0_status & ST0_KUC) + printk("KUc "); + if (regs->cp0_status & ST0_IEC) + printk("IEc "); + } else { + if (regs->cp0_status & ST0_KX) + printk("KX "); + if (regs->cp0_status & ST0_SX) + printk("SX "); + if (regs->cp0_status & ST0_UX) + printk("UX "); + switch (regs->cp0_status & ST0_KSU) { + case KSU_USER: + printk("USER "); + break; + case KSU_SUPERVISOR: + printk("SUPERVISOR "); + break; + case KSU_KERNEL: + printk("KERNEL "); + break; + default: + printk("BAD_MODE "); + break; + } + if (regs->cp0_status & ST0_ERL) + printk("ERL "); + if (regs->cp0_status & ST0_EXL) + printk("EXL "); + if (regs->cp0_status & ST0_IE) + printk("IE "); } - if (regs->cp0_status & ST0_ERL) - printk("ERL "); - if (regs->cp0_status & ST0_EXL) - printk("EXL "); - if (regs->cp0_status & ST0_IE) - printk("IE "); printk("\n"); printk("Cause : %08x\n", cause); -- cgit v1.2.3 From 6e760c8dae7d6c47eff011dd4aad53c94d30494b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 6 Jul 2005 12:08:11 +0000 Subject: Rename CONFIG_CPU_MIPS{32,64} to CONFIG_CPU_MIPS{32|64}_R1. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 46636a2fe98..b2fa607eeeb 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -864,7 +864,7 @@ asmlinkage void cache_parity_error(void) reg_val & (1<<22) ? "E0 " : ""); printk("IDX: 0x%08x\n", reg_val & ((1<<22)-1)); -#if defined(CONFIG_CPU_MIPS32) || defined (CONFIG_CPU_MIPS64) +#if defined(CONFIG_CPU_MIPS32_R1) || defined(CONFIG_CPU_MIPS64_R1) if (reg_val & (1<<22)) printk("DErrAddr0: 0x%0*lx\n", field, read_c0_derraddr0()); -- cgit v1.2.3 From e01402b115cccb6357f956649487aca2c6f7fbba Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 14 Jul 2005 15:57:16 +0000 Subject: More AP / SP bits for the 34K, the Malta bits and things. Still wants a little polishing. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 227 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 214 insertions(+), 13 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index b2fa607eeeb..0a3969aa8dc 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,9 @@ extern int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp, void (*board_be_init)(void); int (*board_be_handler)(struct pt_regs *regs, int is_fixup); +void (*board_nmi_handler_setup)(void); +void (*board_ejtag_handler_setup)(void); +void (*board_bind_eic_interrupt)(int irq, int regset); /* * These constant is for searching for possible module text segments. @@ -813,6 +817,12 @@ asmlinkage void do_reserved(struct pt_regs *regs) (regs->cp0_cause & 0x7f) >> 2); } +asmlinkage void do_default_vi(struct pt_regs *regs) +{ + show_regs(regs); + panic("Caught unexpected vectored interrupt."); +} + /* * Some MIPS CPUs can enable/disable for cache parity detection, but do * it different ways. @@ -921,7 +931,11 @@ void nmi_exception_handler(struct pt_regs *regs) while(1) ; } +#define VECTORSPACING 0x100 /* for EI/VI mode */ + +unsigned long ebase; unsigned long exception_handlers[32]; +unsigned long vi_handlers[64]; /* * As a side effect of the way this is implemented we're limited @@ -935,13 +949,156 @@ void *set_except_vector(int n, void *addr) exception_handlers[n] = handler; if (n == 0 && cpu_has_divec) { - *(volatile u32 *)(CAC_BASE + 0x200) = 0x08000000 | + *(volatile u32 *)(ebase + 0x200) = 0x08000000 | (0x03ffffff & (handler >> 2)); - flush_icache_range(CAC_BASE + 0x200, CAC_BASE + 0x204); + flush_icache_range(ebase + 0x200, ebase + 0x204); + } + return (void *)old_handler; +} + +#ifdef CONFIG_CPU_MIPSR2 +/* + * Shadow register allocation + * FIXME: SMP... + */ + +/* MIPSR2 shadow register sets */ +struct shadow_registers { + spinlock_t sr_lock; /* */ + int sr_supported; /* Number of shadow register sets supported */ + int sr_allocated; /* Bitmap of allocated shadow registers */ +} shadow_registers; + +void mips_srs_init(void) +{ +#ifdef CONFIG_CPU_MIPSR2_SRS + shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1; + printk ("%d MIPSR2 register sets available\n", shadow_registers.sr_supported); +#else + shadow_registers.sr_supported = 1; +#endif + shadow_registers.sr_allocated = 1; /* Set 0 used by kernel */ + spin_lock_init(&shadow_registers.sr_lock); +} + +int mips_srs_max(void) +{ + return shadow_registers.sr_supported; +} + +int mips_srs_alloc (void) +{ + struct shadow_registers *sr = &shadow_registers; + unsigned long flags; + int set; + + spin_lock_irqsave(&sr->sr_lock, flags); + + for (set = 0; set < sr->sr_supported; set++) { + if ((sr->sr_allocated & (1 << set)) == 0) { + sr->sr_allocated |= 1 << set; + spin_unlock_irqrestore(&sr->sr_lock, flags); + return set; + } + } + + /* None available */ + spin_unlock_irqrestore(&sr->sr_lock, flags); + return -1; +} + +void mips_srs_free (int set) +{ + struct shadow_registers *sr = &shadow_registers; + unsigned long flags; + + spin_lock_irqsave(&sr->sr_lock, flags); + sr->sr_allocated &= ~(1 << set); + spin_unlock_irqrestore(&sr->sr_lock, flags); +} + +void *set_vi_srs_handler (int n, void *addr, int srs) +{ + unsigned long handler; + unsigned long old_handler = vi_handlers[n]; + u32 *w; + unsigned char *b; + + if (!cpu_has_veic && !cpu_has_vint) + BUG(); + + if (addr == NULL) { + handler = (unsigned long) do_default_vi; + srs = 0; + } + else + handler = (unsigned long) addr; + vi_handlers[n] = (unsigned long) addr; + + b = (unsigned char *)(ebase + 0x200 + n*VECTORSPACING); + + if (srs >= mips_srs_max()) + panic("Shadow register set %d not supported", srs); + + if (cpu_has_veic) { + if (board_bind_eic_interrupt) + board_bind_eic_interrupt (n, srs); + } + else if (cpu_has_vint) { + /* SRSMap is only defined if shadow sets are implemented */ + if (mips_srs_max() > 1) + change_c0_srsmap (0xf << n*4, srs << n*4); + } + + if (srs == 0) { + /* + * If no shadow set is selected then use the default handler + * that does normal register saving and a standard interrupt exit + */ + + extern char except_vec_vi, except_vec_vi_lui; + extern char except_vec_vi_ori, except_vec_vi_end; + const int handler_len = &except_vec_vi_end - &except_vec_vi; + const int lui_offset = &except_vec_vi_lui - &except_vec_vi; + const int ori_offset = &except_vec_vi_ori - &except_vec_vi; + + if (handler_len > VECTORSPACING) { + /* + * Sigh... panicing won't help as the console + * is probably not configured :( + */ + panic ("VECTORSPACING too small"); + } + + memcpy (b, &except_vec_vi, handler_len); + w = (u32 *)(b + lui_offset); + *w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff); + w = (u32 *)(b + ori_offset); + *w = (*w & 0xffff0000) | ((u32)handler & 0xffff); + flush_icache_range((unsigned long)b, (unsigned long)(b+handler_len)); + } + else { + /* + * In other cases jump directly to the interrupt handler + * + * It is the handlers responsibility to save registers if required + * (eg hi/lo) and return from the exception using "eret" + */ + w = (u32 *)b; + *w++ = 0x08000000 | (((u32)handler >> 2) & 0x03fffff); /* j handler */ + *w = 0; + flush_icache_range((unsigned long)b, (unsigned long)(b+8)); } + return (void *)old_handler; } +void *set_vi_handler (int n, void *addr) +{ + return set_vi_srs_handler (n, addr, 0); +} +#endif + /* * This is used by native signal handling */ @@ -1016,10 +1173,18 @@ void __init per_cpu_trap_init(void) if (cpu_has_dsp) set_c0_status(ST0_MX); +#ifdef CONFIG_CPU_MIPSR2 + write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */ +#endif + /* - * Some MIPS CPUs have a dedicated interrupt vector which reduces the - * interrupt processing overhead. Use it where available. + * Interrupt handling. */ + if (cpu_has_veic || cpu_has_vint) { + write_c0_ebase (ebase); + /* Setting vector spacing enables EI/VI mode */ + change_c0_intctl (0x3e0, VECTORSPACING); + } if (cpu_has_divec) set_c0_cause(CAUSEF_IV); @@ -1035,13 +1200,41 @@ void __init per_cpu_trap_init(void) tlb_init(); } +/* Install CPU exception handler */ +void __init set_handler (unsigned long offset, void *addr, unsigned long size) +{ + memcpy((void *)(ebase + offset), addr, size); + flush_icache_range(ebase + offset, ebase + offset + size); +} + +/* Install uncached CPU exception handler */ +void __init set_uncached_handler (unsigned long offset, void *addr, unsigned long size) +{ +#ifdef CONFIG_32BIT + unsigned long uncached_ebase = KSEG1ADDR(ebase); +#endif +#ifdef CONFIG_64BIT + unsigned long uncached_ebase = TO_UNCAC(ebase); +#endif + + memcpy((void *)(uncached_ebase + offset), addr, size); +} + void __init trap_init(void) { extern char except_vec3_generic, except_vec3_r4000; - extern char except_vec_ejtag_debug; extern char except_vec4; unsigned long i; + if (cpu_has_veic || cpu_has_vint) + ebase = (unsigned long) alloc_bootmem_low_pages (0x200 + VECTORSPACING*64); + else + ebase = CAC_BASE; + +#ifdef CONFIG_CPU_MIPSR2 + mips_srs_init(); +#endif + per_cpu_trap_init(); /* @@ -1049,7 +1242,7 @@ void __init trap_init(void) * This will be overriden later as suitable for a particular * configuration. */ - memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80); + set_handler(0x180, &except_vec3_generic, 0x80); /* * Setup default vectors @@ -1061,8 +1254,8 @@ void __init trap_init(void) * Copy the EJTAG debug exception vector handler code to it's final * destination. */ - if (cpu_has_ejtag) - memcpy((void *)(CAC_BASE + 0x300), &except_vec_ejtag_debug, 0x80); + if (cpu_has_ejtag && board_ejtag_handler_setup) + board_ejtag_handler_setup (); /* * Only some CPUs have the watch exceptions. @@ -1071,11 +1264,15 @@ void __init trap_init(void) set_except_vector(23, handle_watch); /* - * Some MIPS CPUs have a dedicated interrupt vector which reduces the - * interrupt processing overhead. Use it where available. + * Initialise interrupt handlers */ - if (cpu_has_divec) - memcpy((void *)(CAC_BASE + 0x200), &except_vec4, 0x8); + if (cpu_has_veic || cpu_has_vint) { + int nvec = cpu_has_veic ? 64 : 8; + for (i = 0; i < nvec; i++) + set_vi_handler (i, NULL); + } + else if (cpu_has_divec) + set_handler(0x200, &except_vec4, 0x8); /* * Some CPUs can enable/disable for cache parity detection, but does @@ -1122,6 +1319,10 @@ void __init trap_init(void) //set_except_vector(15, handle_ndc); } + + if (board_nmi_handler_setup) + board_nmi_handler_setup(); + if (cpu_has_fpu && !cpu_has_nofpuex) set_except_vector(15, handle_fpe); @@ -1146,5 +1347,5 @@ void __init trap_init(void) signal32_init(); #endif - flush_icache_range(CAC_BASE, CAC_BASE + 0x400); + flush_icache_range(ebase, ebase + 0x400); } -- cgit v1.2.3 From 1d40cfcd3442a53e98468cdb3e6d4d9a568d76cf Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 15 Jul 2005 15:23:23 +0000 Subject: Avoid SMP cacheflushes. This is a minor optimization of startup but will also avoid smp_call_function from doing stupid things when called from a CPU that is not yet marked online. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 0a3969aa8dc..519b8f18eed 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1150,6 +1150,7 @@ static inline void signal32_init(void) extern void cpu_cache_init(void); extern void tlb_init(void); +extern void flush_tlb_handlers(void); void __init per_cpu_trap_init(void) { @@ -1348,4 +1349,5 @@ void __init trap_init(void) #endif flush_icache_range(ebase, ebase + 0x400); + flush_tlb_handlers(); } -- cgit v1.2.3 From d03d0a57754cb820d318d2234c60b728eb38a94d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 17 Aug 2005 13:44:26 +0000 Subject: MT bulletproofing. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 519b8f18eed..876aff71cd2 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1186,8 +1186,14 @@ void __init per_cpu_trap_init(void) /* Setting vector spacing enables EI/VI mode */ change_c0_intctl (0x3e0, VECTORSPACING); } - if (cpu_has_divec) - set_c0_cause(CAUSEF_IV); + if (cpu_has_divec) { + if (cpu_has_mipsmt) { + unsigned int vpflags = dvpe(); + set_c0_cause(CAUSEF_IV); + evpe(vpflags); + } else + set_c0_cause(CAUSEF_IV); + } cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; TLBMISS_HANDLER_SETUP(); -- cgit v1.2.3 From 340ee4b98c0543b5632cac975a7449a2d28762d8 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 17 Aug 2005 17:44:08 +0000 Subject: Virtual SMP support for the 34K. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 876aff71cd2..e38f24b2b3d 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -56,6 +58,7 @@ extern asmlinkage void handle_tr(void); extern asmlinkage void handle_fpe(void); extern asmlinkage void handle_mdmx(void); extern asmlinkage void handle_watch(void); +extern asmlinkage void handle_mt(void); extern asmlinkage void handle_dsp(void); extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); @@ -797,6 +800,14 @@ asmlinkage void do_mcheck(struct pt_regs *regs) (regs->cp0_status & ST0_TS) ? "" : "not "); } +asmlinkage void do_mt(struct pt_regs *regs) +{ + die_if_kernel("MIPS MT Thread exception in kernel", regs); + + force_sig(SIGILL, current); +} + + asmlinkage void do_dsp(struct pt_regs *regs) { if (cpu_has_dsp) @@ -1338,6 +1349,9 @@ void __init trap_init(void) if (cpu_has_mcheck) set_except_vector(24, handle_mcheck); + if (cpu_has_mipsmt) + set_except_vector(25, handle_mt); + if (cpu_has_dsp) set_except_vector(26, handle_dsp); -- cgit v1.2.3 From ec917c2c1ab4359a1d438e62daeb50cc42e632e1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 7 Oct 2005 16:58:15 +0100 Subject: Fixup a few lose ends in explicit support for MIPS R1/R2. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index e38f24b2b3d..eccae819160 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -885,7 +885,7 @@ asmlinkage void cache_parity_error(void) reg_val & (1<<22) ? "E0 " : ""); printk("IDX: 0x%08x\n", reg_val & ((1<<22)-1)); -#if defined(CONFIG_CPU_MIPS32_R1) || defined(CONFIG_CPU_MIPS64_R1) +#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) if (reg_val & (1<<22)) printk("DErrAddr0: 0x%0*lx\n", field, read_c0_derraddr0()); -- cgit v1.2.3 From 178086c86ac9738a76f1462e9ee4cbe8fd3b8c51 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 13 Oct 2005 17:07:54 +0100 Subject: Don't print file name and line in die and die_if_kernel. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index eccae819160..a3c00512696 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -276,30 +276,18 @@ void show_registers(struct pt_regs *regs) static DEFINE_SPINLOCK(die_lock); -NORET_TYPE void ATTRIB_NORET __die(const char * str, struct pt_regs * regs, - const char * file, const char * func, - unsigned long line) +NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs) { static int die_counter; console_verbose(); spin_lock_irq(&die_lock); - printk("%s", str); - if (file && func) - printk(" in %s:%s, line %ld", file, func, line); - printk("[#%d]:\n", ++die_counter); + printk("%s[#%d]:\n", str, ++die_counter); show_registers(regs); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } -void __die_if_kernel(const char * str, struct pt_regs * regs, - const char * file, const char * func, unsigned long line) -{ - if (!user_mode(regs)) - __die(str, regs, file, func, line); -} - extern const struct exception_table_entry __start___dbe_table[]; extern const struct exception_table_entry __stop___dbe_table[]; -- cgit v1.2.3 From 12616ed202ba66af6e1386df02d06c72d7386339 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 18 Oct 2005 10:26:46 +0100 Subject: FPU emulator garbage collection. First argument of fpu_emulator_cop1Handler() was unused. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index a3c00512696..6f3ff969068 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -63,7 +63,7 @@ extern asmlinkage void handle_dsp(void); extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); -extern int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp, +extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx); void (*board_be_init)(void); @@ -589,7 +589,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) preempt_enable(); /* Run the emulator */ - sig = fpu_emulator_cop1Handler (0, regs, + sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu.soft); preempt_disable(); @@ -743,7 +743,7 @@ asmlinkage void do_cpu(struct pt_regs *regs) preempt_enable(); if (!cpu_has_fpu) { - int sig = fpu_emulator_cop1Handler(0, regs, + int sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu.soft); if (sig) force_sig(sig, current); -- cgit v1.2.3