diff options
| -rw-r--r-- | arch/mips/cavium-octeon/Makefile | 2 | ||||
| -rw-r--r-- | arch/mips/cavium-octeon/cpu.c | 52 | ||||
| -rw-r--r-- | arch/mips/include/asm/cop2.h | 23 | ||||
| -rw-r--r-- | arch/mips/include/asm/octeon/octeon.h | 1 | ||||
| -rw-r--r-- | arch/mips/kernel/traps.c | 60 | ||||
| -rw-r--r-- | arch/mips/kernel/unaligned.c | 25 |
6 files changed, 140 insertions, 23 deletions
diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile index 139436280520..3e9876317e61 100644 --- a/arch/mips/cavium-octeon/Makefile +++ b/arch/mips/cavium-octeon/Makefile | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | # Copyright (C) 2005-2009 Cavium Networks | 9 | # Copyright (C) 2005-2009 Cavium Networks |
| 10 | # | 10 | # |
| 11 | 11 | ||
| 12 | obj-y := setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o | 12 | obj-y := cpu.o setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o |
| 13 | obj-y += dma-octeon.o flash_setup.o | 13 | obj-y += dma-octeon.o flash_setup.o |
| 14 | obj-y += octeon-memcpy.o | 14 | obj-y += octeon-memcpy.o |
| 15 | 15 | ||
diff --git a/arch/mips/cavium-octeon/cpu.c b/arch/mips/cavium-octeon/cpu.c new file mode 100644 index 000000000000..b6df5387e855 --- /dev/null +++ b/arch/mips/cavium-octeon/cpu.c | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2009 Wind River Systems, | ||
| 7 | * written by Ralf Baechle <ralf@linux-mips.org> | ||
| 8 | */ | ||
| 9 | #include <linux/init.h> | ||
| 10 | #include <linux/irqflags.h> | ||
| 11 | #include <linux/notifier.h> | ||
| 12 | #include <linux/prefetch.h> | ||
| 13 | #include <linux/sched.h> | ||
| 14 | |||
| 15 | #include <asm/cop2.h> | ||
| 16 | #include <asm/current.h> | ||
| 17 | #include <asm/mipsregs.h> | ||
| 18 | #include <asm/page.h> | ||
| 19 | #include <asm/octeon/octeon.h> | ||
| 20 | |||
| 21 | static int cnmips_cu2_call(struct notifier_block *nfb, unsigned long action, | ||
| 22 | void *data) | ||
| 23 | { | ||
| 24 | unsigned long flags; | ||
| 25 | unsigned int status; | ||
| 26 | |||
| 27 | switch (action) { | ||
| 28 | case CU2_EXCEPTION: | ||
| 29 | prefetch(¤t->thread.cp2); | ||
| 30 | local_irq_save(flags); | ||
| 31 | KSTK_STATUS(current) |= ST0_CU2; | ||
| 32 | status = read_c0_status(); | ||
| 33 | write_c0_status(status | ST0_CU2); | ||
| 34 | octeon_cop2_restore(&(current->thread.cp2)); | ||
| 35 | write_c0_status(status & ~ST0_CU2); | ||
| 36 | local_irq_restore(flags); | ||
| 37 | |||
| 38 | return NOTIFY_BAD; /* Don't call default notifier */ | ||
| 39 | } | ||
| 40 | |||
| 41 | return NOTIFY_OK; /* Let default notifier send signals */ | ||
| 42 | } | ||
| 43 | |||
| 44 | static struct notifier_block cnmips_cu2_notifier = { | ||
| 45 | .notifier_call = cnmips_cu2_call, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static int cnmips_cu2_setup(void) | ||
| 49 | { | ||
| 50 | return register_cu2_notifier(&cnmips_cu2_notifier); | ||
| 51 | } | ||
| 52 | 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 000000000000..6b04c98b7fad --- /dev/null +++ b/arch/mips/include/asm/cop2.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2009 Wind River Systems, | ||
| 7 | * written by Ralf Baechle <ralf@linux-mips.org> | ||
| 8 | */ | ||
| 9 | #ifndef __ASM_COP2_H | ||
| 10 | #define __ASM_COP2_H | ||
| 11 | |||
| 12 | enum cu2_ops { | ||
| 13 | CU2_EXCEPTION, | ||
| 14 | CU2_LWC2_OP, | ||
| 15 | CU2_LDC2_OP, | ||
| 16 | CU2_SWC2_OP, | ||
| 17 | CU2_SDC2_OP, | ||
| 18 | }; | ||
| 19 | |||
| 20 | extern int register_cu2_notifier(struct notifier_block *nb); | ||
| 21 | extern int cu2_notifier_call_chain(unsigned long val, void *v); | ||
| 22 | |||
| 23 | #endif /* __ASM_COP2_H */ | ||
diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h index cac9b1a206fc..4d0a8c61fc3e 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; | |||
| 47 | extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state); | 47 | extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state); |
| 48 | extern void octeon_crypto_disable(struct octeon_cop2_state *state, | 48 | extern void octeon_crypto_disable(struct octeon_cop2_state *state, |
| 49 | unsigned long flags); | 49 | unsigned long flags); |
| 50 | extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task); | ||
| 50 | 51 | ||
| 51 | extern void octeon_init_cvmcount(void); | 52 | extern void octeon_init_cvmcount(void); |
| 52 | 53 | ||
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 0a18b4c62afb..9fe21fb65305 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
| @@ -25,10 +25,12 @@ | |||
| 25 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
| 26 | #include <linux/kgdb.h> | 26 | #include <linux/kgdb.h> |
| 27 | #include <linux/kdebug.h> | 27 | #include <linux/kdebug.h> |
| 28 | #include <linux/notifier.h> | ||
| 28 | 29 | ||
| 29 | #include <asm/bootinfo.h> | 30 | #include <asm/bootinfo.h> |
| 30 | #include <asm/branch.h> | 31 | #include <asm/branch.h> |
| 31 | #include <asm/break.h> | 32 | #include <asm/break.h> |
| 33 | #include <asm/cop2.h> | ||
| 32 | #include <asm/cpu.h> | 34 | #include <asm/cpu.h> |
| 33 | #include <asm/dsp.h> | 35 | #include <asm/dsp.h> |
| 34 | #include <asm/fpu.h> | 36 | #include <asm/fpu.h> |
| @@ -79,10 +81,6 @@ extern asmlinkage void handle_reserved(void); | |||
| 79 | extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, | 81 | extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, |
| 80 | struct mips_fpu_struct *ctx, int has_fpu); | 82 | struct mips_fpu_struct *ctx, int has_fpu); |
| 81 | 83 | ||
| 82 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | ||
| 83 | extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task); | ||
| 84 | #endif | ||
| 85 | |||
| 86 | void (*board_be_init)(void); | 84 | void (*board_be_init)(void); |
| 87 | int (*board_be_handler)(struct pt_regs *regs, int is_fixup); | 85 | int (*board_be_handler)(struct pt_regs *regs, int is_fixup); |
| 88 | void (*board_nmi_handler_setup)(void); | 86 | void (*board_nmi_handler_setup)(void); |
| @@ -857,6 +855,44 @@ static void mt_ase_fp_affinity(void) | |||
| 857 | #endif /* CONFIG_MIPS_MT_FPAFF */ | 855 | #endif /* CONFIG_MIPS_MT_FPAFF */ |
| 858 | } | 856 | } |
| 859 | 857 | ||
| 858 | /* | ||
| 859 | * No lock; only written during early bootup by CPU 0. | ||
| 860 | */ | ||
| 861 | static RAW_NOTIFIER_HEAD(cu2_chain); | ||
| 862 | |||
| 863 | int __ref register_cu2_notifier(struct notifier_block *nb) | ||
| 864 | { | ||
| 865 | return raw_notifier_chain_register(&cu2_chain, nb); | ||
| 866 | } | ||
| 867 | |||
| 868 | int cu2_notifier_call_chain(unsigned long val, void *v) | ||
| 869 | { | ||
| 870 | return raw_notifier_call_chain(&cu2_chain, val, v); | ||
| 871 | } | ||
| 872 | |||
| 873 | static int default_cu2_call(struct notifier_block *nfb, unsigned long action, | ||
| 874 | void *data) | ||
| 875 | { | ||
| 876 | struct pt_regs *regs = data; | ||
| 877 | |||
| 878 | switch (action) { | ||
| 879 | default: | ||
| 880 | die_if_kernel("Unhandled kernel unaligned access or invalid " | ||
| 881 | "instruction", regs); | ||
| 882 | /* Fall through */ | ||
| 883 | |||
| 884 | case CU2_EXCEPTION: | ||
| 885 | force_sig(SIGILL, current); | ||
| 886 | } | ||
| 887 | |||
| 888 | return NOTIFY_OK; | ||
| 889 | } | ||
| 890 | |||
| 891 | static struct notifier_block default_cu2_notifier = { | ||
| 892 | .notifier_call = default_cu2_call, | ||
| 893 | .priority = 0x80000000, /* Run last */ | ||
| 894 | }; | ||
| 895 | |||
| 860 | asmlinkage void do_cpu(struct pt_regs *regs) | 896 | asmlinkage void do_cpu(struct pt_regs *regs) |
| 861 | { | 897 | { |
| 862 | unsigned int __user *epc; | 898 | unsigned int __user *epc; |
| @@ -920,17 +956,9 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
| 920 | return; | 956 | return; |
| 921 | 957 | ||
| 922 | case 2: | 958 | case 2: |
| 923 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | 959 | raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs); |
| 924 | prefetch(¤t->thread.cp2); | 960 | break; |
| 925 | local_irq_save(flags); | 961 | |
| 926 | KSTK_STATUS(current) |= ST0_CU2; | ||
| 927 | status = read_c0_status(); | ||
| 928 | write_c0_status(status | ST0_CU2); | ||
| 929 | octeon_cop2_restore(&(current->thread.cp2)); | ||
| 930 | write_c0_status(status & ~ST0_CU2); | ||
| 931 | local_irq_restore(flags); | ||
| 932 | return; | ||
| 933 | #endif | ||
| 934 | case 3: | 962 | case 3: |
| 935 | break; | 963 | break; |
| 936 | } | 964 | } |
| @@ -1760,4 +1788,6 @@ void __init trap_init(void) | |||
| 1760 | flush_tlb_handlers(); | 1788 | flush_tlb_handlers(); |
| 1761 | 1789 | ||
| 1762 | sort_extable(__start___dbe_table, __stop___dbe_table); | 1790 | sort_extable(__start___dbe_table, __stop___dbe_table); |
| 1791 | |||
| 1792 | register_cu2_notifier(&default_cu2_notifier); | ||
| 1763 | } | 1793 | } |
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 67bd626942ab..69b039ca8d83 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c | |||
| @@ -81,6 +81,7 @@ | |||
| 81 | #include <asm/asm.h> | 81 | #include <asm/asm.h> |
| 82 | #include <asm/branch.h> | 82 | #include <asm/branch.h> |
| 83 | #include <asm/byteorder.h> | 83 | #include <asm/byteorder.h> |
| 84 | #include <asm/cop2.h> | ||
| 84 | #include <asm/inst.h> | 85 | #include <asm/inst.h> |
| 85 | #include <asm/uaccess.h> | 86 | #include <asm/uaccess.h> |
| 86 | #include <asm/system.h> | 87 | #include <asm/system.h> |
| @@ -451,17 +452,27 @@ static void emulate_load_store_insn(struct pt_regs *regs, | |||
| 451 | */ | 452 | */ |
| 452 | goto sigbus; | 453 | goto sigbus; |
| 453 | 454 | ||
| 455 | /* | ||
| 456 | * COP2 is available to implementor for application specific use. | ||
| 457 | * It's up to applications to register a notifier chain and do | ||
| 458 | * whatever they have to do, including possible sending of signals. | ||
| 459 | */ | ||
| 454 | case lwc2_op: | 460 | case lwc2_op: |
| 461 | cu2_notifier_call_chain(CU2_LWC2_OP, regs); | ||
| 462 | break; | ||
| 463 | |||
| 455 | case ldc2_op: | 464 | case ldc2_op: |
| 465 | cu2_notifier_call_chain(CU2_LDC2_OP, regs); | ||
| 466 | break; | ||
| 467 | |||
| 456 | case swc2_op: | 468 | case swc2_op: |
| 469 | cu2_notifier_call_chain(CU2_SWC2_OP, regs); | ||
| 470 | break; | ||
| 471 | |||
| 457 | case sdc2_op: | 472 | case sdc2_op: |
| 458 | /* | 473 | cu2_notifier_call_chain(CU2_SDC2_OP, regs); |
| 459 | * These are the coprocessor 2 load/stores. The current | 474 | break; |
| 460 | * implementations don't use cp2 and cp2 should always be | 475 | |
| 461 | * disabled in c0_status. So send SIGILL. | ||
| 462 | * (No longer true: The Sony Praystation uses cp2 for | ||
| 463 | * 3D matrix operations. Dunno if that thingy has a MMU ...) | ||
| 464 | */ | ||
| 465 | default: | 476 | default: |
| 466 | /* | 477 | /* |
| 467 | * Pheeee... We encountered an yet unknown instruction or | 478 | * Pheeee... We encountered an yet unknown instruction or |
