diff options
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r-- | arch/mips/kernel/traps.c | 97 |
1 files changed, 61 insertions, 36 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index a7a17eb9bfc..80ea4fa95bd 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -39,7 +39,6 @@ #include <asm/traps.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> -#include <asm/watch.h> #include <asm/types.h> #include <asm/stacktrace.h> @@ -70,6 +69,7 @@ extern asmlinkage void handle_reserved(void); extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, int has_fpu); +void (*board_watchpoint_handler)(struct pt_regs *regs); void (*board_be_init)(void); int (*board_be_handler)(struct pt_regs *regs, int is_fixup); void (*board_nmi_handler_setup)(void); @@ -311,7 +311,7 @@ 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) +void __noreturn die(const char * str, struct pt_regs * regs) { static int die_counter; #ifdef CONFIG_MIPS_MT_SMTC @@ -753,6 +753,33 @@ asmlinkage void do_ri(struct pt_regs *regs) force_sig(SIGILL, current); } +/* + * MIPS MT processors may have fewer FPU contexts than CPU threads. If we've + * emulated more than some threshold number of instructions, force migration to + * a "CPU" that has FP support. + */ +static void mt_ase_fp_affinity(void) +{ +#ifdef CONFIG_MIPS_MT_FPAFF + if (mt_fpemul_threshold > 0 && + ((current->thread.emulated_fp++ > mt_fpemul_threshold))) { + /* + * If there's no FPU present, or if the application has already + * restricted the allowed set to exclude any CPUs with FPUs, + * we'll skip the procedure. + */ + if (cpus_intersects(current->cpus_allowed, mt_fpu_cpumask)) { + cpumask_t tmask; + + cpus_and(tmask, current->thread.user_cpus_allowed, + mt_fpu_cpumask); + set_cpus_allowed(current, tmask); + current->thread.mflags |= MF_FPUBOUND; + } + } +#endif /* CONFIG_MIPS_MT_FPAFF */ +} + asmlinkage void do_cpu(struct pt_regs *regs) { unsigned int cpid; @@ -786,36 +813,8 @@ asmlinkage void do_cpu(struct pt_regs *regs) ¤t->thread.fpu, 0); if (sig) force_sig(sig, current); -#ifdef CONFIG_MIPS_MT_FPAFF - else { - /* - * MIPS MT processors may have fewer FPU contexts - * than CPU threads. If we've emulated more than - * some threshold number of instructions, force - * migration to a "CPU" that has FP support. - */ - if(mt_fpemul_threshold > 0 - && ((current->thread.emulated_fp++ - > mt_fpemul_threshold))) { - /* - * If there's no FPU present, or if the - * application has already restricted - * the allowed set to exclude any CPUs - * with FPUs, we'll skip the procedure. - */ - if (cpus_intersects(current->cpus_allowed, - mt_fpu_cpumask)) { - cpumask_t tmask; - - cpus_and(tmask, - current->thread.user_cpus_allowed, - mt_fpu_cpumask); - set_cpus_allowed(current, tmask); - current->thread.mflags |= MF_FPUBOUND; - } - } - } -#endif /* CONFIG_MIPS_MT_FPAFF */ + else + mt_ase_fp_affinity(); } return; @@ -835,6 +834,11 @@ asmlinkage void do_mdmx(struct pt_regs *regs) asmlinkage void do_watch(struct pt_regs *regs) { + if (board_watchpoint_handler) { + (*board_watchpoint_handler)(regs); + return; + } + /* * We use the watch exception where available to detect stack * overflows. @@ -1343,16 +1347,20 @@ void __init per_cpu_trap_init(void) set_c0_status(ST0_MX); #ifdef CONFIG_CPU_MIPSR2 - write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */ + if (cpu_has_mips_r2) { + unsigned int enable = 0x0000000f; + + if (cpu_has_userlocal) + enable |= (1 << 29); + + write_c0_hwrena(enable); + } #endif #ifdef CONFIG_MIPS_MT_SMTC if (!secondaryTC) { #endif /* CONFIG_MIPS_MT_SMTC */ - /* - * Interrupt handling. - */ if (cpu_has_veic || cpu_has_vint) { write_c0_ebase (ebase); /* Setting vector spacing enables EI/VI mode */ @@ -1366,6 +1374,23 @@ void __init per_cpu_trap_init(void) } else set_c0_cause(CAUSEF_IV); } + + /* + * Before R2 both interrupt numbers were fixed to 7, so on R2 only: + * + * o read IntCtl.IPTI to determine the timer interrupt + * o read IntCtl.IPPCI to determine the performance counter interrupt + */ + if (cpu_has_mips_r2) { + cp0_compare_irq = (read_c0_intctl () >> 29) & 7; + cp0_perfcount_irq = (read_c0_intctl () >> 26) & 7; + if (cp0_perfcount_irq == cp0_compare_irq) + cp0_perfcount_irq = -1; + } else { + cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ; + cp0_perfcount_irq = -1; + } + #ifdef CONFIG_MIPS_MT_SMTC } #endif /* CONFIG_MIPS_MT_SMTC */ |