diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile index 13943628052..3e9876317e6 100644 --- a/arch/mips/cavium-octeon/Makefile +++ b/arch/mips/cavium-octeon/Makefile @@ -9,7 +9,7 @@ # Copyright (C) 2005-2009 Cavium Networks # -obj-y := setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o +obj-y := cpu.o setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o obj-y += dma-octeon.o flash_setup.o obj-y += octeon-memcpy.o diff --git a/arch/mips/cavium-octeon/cpu.c b/arch/mips/cavium-octeon/cpu.c new file mode 100644 index 00000000000..b6df5387e85 --- /dev/null +++ b/arch/mips/cavium-octeon/cpu.c @@ -0,0 +1,52 @@ +/* + * 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 + * for more details. + * + * Copyright (C) 2009 Wind River Systems, + * written by Ralf Baechle + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static int cnmips_cu2_call(struct notifier_block *nfb, unsigned long action, + void *data) +{ + unsigned long flags; + unsigned int status; + + switch (action) { + case CU2_EXCEPTION: + prefetch(¤t->thread.cp2); + local_irq_save(flags); + KSTK_STATUS(current) |= ST0_CU2; + status = read_c0_status(); + write_c0_status(status | ST0_CU2); + octeon_cop2_restore(&(current->thread.cp2)); + write_c0_status(status & ~ST0_CU2); + local_irq_restore(flags); + + return NOTIFY_BAD; /* Don't call default notifier */ + } + + return NOTIFY_OK; /* Let default notifier send signals */ +} + +static struct notifier_block cnmips_cu2_notifier = { + .notifier_call = cnmips_cu2_call, +}; + +static int cnmips_cu2_setup(void) +{ + return register_cu2_notifier(&cnmips_cu2_notifier); +} +early_initcall(cnmips_cu2_setup); diff --git a/arch/mips/include/asm/cop2.h b/arch/mips/include/asm/cop2.h new file mode 100644 index 00000000000..6b04c98b7fa --- /dev/null +++ b/arch/mips/include/asm/cop2.h @@ -0,0 +1,23 @@ +/* + * 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 + * for more details. + * + * Copyright (C) 2009 Wind River Systems, + * written by Ralf Baechle + */ +#ifndef __ASM_COP2_H +#define __ASM_COP2_H + +enum cu2_ops { + CU2_EXCEPTION, + CU2_LWC2_OP, + CU2_LDC2_OP, + CU2_SWC2_OP, + CU2_SDC2_OP, +}; + +extern int register_cu2_notifier(struct notifier_block *nb); +extern int cu2_notifier_call_chain(unsigned long val, void *v); + +#endif /* __ASM_COP2_H */ diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h index cac9b1a206f..4d0a8c61fc3 100644 --- a/arch/mips/include/asm/octeon/octeon.h +++ b/arch/mips/include/asm/octeon/octeon.h @@ -47,6 +47,7 @@ struct octeon_cop2_state; extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state); extern void octeon_crypto_disable(struct octeon_cop2_state *state, unsigned long flags); +extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task); extern void octeon_init_cvmcount(void); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 0a18b4c62af..9fe21fb6530 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -25,10 +25,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -79,10 +81,6 @@ extern asmlinkage void handle_reserved(void); extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, int has_fpu); -#ifdef CONFIG_CPU_CAVIUM_OCTEON -extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task); -#endif - void (*board_be_init)(void); int (*board_be_handler)(struct pt_regs *regs, int is_fixup); void (*board_nmi_handler_setup)(void); @@ -857,6 +855,44 @@ static void mt_ase_fp_affinity(void) #endif /* CONFIG_MIPS_MT_FPAFF */ } +/* + * No lock; only written during early bootup by CPU 0. + */ +static RAW_NOTIFIER_HEAD(cu2_chain); + +int __ref register_cu2_notifier(struct notifier_block *nb) +{ + return raw_notifier_chain_register(&cu2_chain, nb); +} + +int cu2_notifier_call_chain(unsigned long val, void *v) +{ + return raw_notifier_call_chain(&cu2_chain, val, v); +} + +static int default_cu2_call(struct notifier_block *nfb, unsigned long action, + void *data) +{ + struct pt_regs *regs = data; + + switch (action) { + default: + die_if_kernel("Unhandled kernel unaligned access or invalid " + "instruction", regs); + /* Fall through */ + + case CU2_EXCEPTION: + force_sig(SIGILL, current); + } + + return NOTIFY_OK; +} + +static struct notifier_block default_cu2_notifier = { + .notifier_call = default_cu2_call, + .priority = 0x80000000, /* Run last */ +}; + asmlinkage void do_cpu(struct pt_regs *regs) { unsigned int __user *epc; @@ -920,17 +956,9 @@ asmlinkage void do_cpu(struct pt_regs *regs) return; case 2: -#ifdef CONFIG_CPU_CAVIUM_OCTEON - prefetch(¤t->thread.cp2); - local_irq_save(flags); - KSTK_STATUS(current) |= ST0_CU2; - status = read_c0_status(); - write_c0_status(status | ST0_CU2); - octeon_cop2_restore(&(current->thread.cp2)); - write_c0_status(status & ~ST0_CU2); - local_irq_restore(flags); - return; -#endif + raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs); + break; + case 3: break; } @@ -1760,4 +1788,6 @@ void __init trap_init(void) flush_tlb_handlers(); sort_extable(__start___dbe_table, __stop___dbe_table); + + register_cu2_notifier(&default_cu2_notifier); } diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 67bd626942a..69b039ca8d8 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -81,6 +81,7 @@ #include #include #include +#include #include #include #include @@ -451,17 +452,27 @@ static void emulate_load_store_insn(struct pt_regs *regs, */ goto sigbus; + /* + * COP2 is available to implementor for application specific use. + * It's up to applications to register a notifier chain and do + * whatever they have to do, including possible sending of signals. + */ case lwc2_op: + cu2_notifier_call_chain(CU2_LWC2_OP, regs); + break; + case ldc2_op: + cu2_notifier_call_chain(CU2_LDC2_OP, regs); + break; + case swc2_op: + cu2_notifier_call_chain(CU2_SWC2_OP, regs); + break; + case sdc2_op: - /* - * These are the coprocessor 2 load/stores. The current - * implementations don't use cp2 and cp2 should always be - * disabled in c0_status. So send SIGILL. - * (No longer true: The Sony Praystation uses cp2 for - * 3D matrix operations. Dunno if that thingy has a MMU ...) - */ + cu2_notifier_call_chain(CU2_SDC2_OP, regs); + break; + default: /* * Pheeee... We encountered an yet unknown instruction or